www.pudn.com > Acd.rar > AcdSmpl.c


////////////////////////////////////////////////////////////////////////////// 
// 
//  ACDSMPL.C 
// 
//  Handles all the UI for ACDSample 
// 
////////////////////////////////////////////////////////////////////////////// 
 
#include  
#include  
#include  
#include  
#include  
#include "resource.h" 
#include "acdsmpl.h" 
 
 
////////////////////////////////////////////////////////////////////////////// 
//  PROTOTYPES 
////////////////////////////////////////////////////////////////////////////// 
static BOOL CreateMainWindow (int nCmdShow); 
 
static LRESULT CALLBACK MainDlgProc (HWND   hwnd, 
                                     UINT   uMsg, 
                                     WPARAM wParam, 
                                     LPARAM lParam); 
void MySetWindow(HWND, int); 
void MySaveWindow(HWND); 
BOOL ResizeWindows(BOOL bSizeBar, DWORD dwBarLocation); 
HTREEITEM AddItemToTree(HTREEITEM hParent, 
                        LPTSTR lpszName, 
                        LPARAM lParam, 
                        HTREEITEM * phItem); 
BOOL DoPopupMenu(HTREEITEM hItem, POINT pt); 
BOOL DeleteLeafAndStruct(HTREEITEM hItem); 
BOOL CALLBACK ChangeGroupDlgProc(HWND   hWnd, 
                            UINT   uMsg, 
                            WPARAM wParam, 
                            LPARAM lParam); 
BOOL CALLBACK ChangeAgentDlgProc(HWND   hWnd, 
                            UINT   uMsg, 
                            WPARAM wParam, 
                            LPARAM lParam); 
BOOL CALLBACK AddGroupDlgProc(HWND   hWnd, 
                         UINT   uMsg, 
                         WPARAM wParam, 
                         LPARAM lParam); 
BOOL CALLBACK AddAgentDlgProc(HWND   hWnd, 
                         UINT   uMsg, 
                         WPARAM wParam, 
                         LPARAM lParam); 
LRESULT DoCommand(WPARAM wParam, LPARAM lParam); 
void AddGroupsToMenu(HTREEITEM hItem, 
                     HMENU hMenu); 
BOOL CALLBACK GroupAddToListProc(HWND   hWnd, 
                            UINT   uMsg, 
                            WPARAM wParam, 
                            LPARAM lParam); 
BOOL CALLBACK AgentAddToListProc(HWND   hWnd, 
                            UINT   uMsg, 
                            WPARAM wParam, 
                            LPARAM lParam); 
BOOL BuildLineList(HWND hWnd, 
                   DWORD dwDeviceID); 
BOOL BuildAddressList(HWND hWnd, 
                      HWND hParentWnd, 
                      DWORD dwDeviceID); 
BOOL InitializeTapi(); 
BOOL CleanUp(); 
BOOL UpdateGroupLeaf(PGROUP pGroup); 
BOOL DoAgentView(); 
BOOL DoGroupView(); 
BOOL ReadInFile(); 
BOOL WriteToDisk(); 
 
 
 
////////////////////////////////////////////////////////////////////////////// 
//  GLOBALS 
////////////////////////////////////////////////////////////////////////////// 
ACDGLOBALS      g; 
 
TCHAR gszACDSampleKey[]     = TEXT("Software\\Microsoft\\ACDSample"); 
TCHAR gszPlacementValue[]   = TEXT("WindowPlacement"); 
TCHAR gszBarLocation[]      = TEXT("BarLocation"); 
 
 
 
////////////////////////////////////////////////////////////////////////////// 
// 
// WinMain() 
// 
////////////////////////////////////////////////////////////////////////////// 
int WINAPI WinMain (HINSTANCE hInstance, 
                    HINSTANCE hPrevInstance, 
                    LPSTR     lpszCmdLine, 
                    int       nCmdShow) 
{ 
    MSG msg; 
 
    // initialize global variables 
    g.hInstance = hInstance; 
    g.pAgents = NULL; 
    g.pGroups = NULL; 
 
    // init tapi stuff 
    if (!InitializeTapi()) 
    { 
        MessageBox(NULL, 
                   TEXT("TAPI could not be initialized.\nVerify that") 
                   TEXT("your machine has TAPI devices installed"), 
                   TEXT("Cannot start ACDSMPL"), 
                   MB_OK); 
    } 
 
    if (!CreateMainWindow(nCmdShow)) 
    { 
        return 0; 
    } 
 
    // main message loop 
    while (GetMessage(&msg, NULL, 0, 0)) 
    { 
        if (!IsDialogMessage(g.hMainWnd, 
                             &msg)) 
        { 
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        } 
    } 
 
    return 1; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// 
//  CreateMainWindow() 
// 
////////////////////////////////////////////////////////////////////////////// 
BOOL CreateMainWindow (int nCmdShow) 
{ 
 
    // InitCommonControls for TreeView control 
    InitCommonControls(); 
 
    // Create the main window 
    g.hMainWnd = CreateDialog(g.hInstance, 
                             MAKEINTRESOURCE(IDD_MAINDLG), 
                             NULL, 
                             MainDlgProc); 
 
    if (g.hMainWnd == NULL) 
    { 
        return FALSE; 
    } 
 
    // restore default location 
    MySetWindow(g.hMainWnd, nCmdShow); 
     
    // store global hwnds 
    g.hTreeWnd = GetDlgItem(g.hMainWnd, 
                            IDC_TREEWND); 
 
    g.hLogWnd = GetDlgItem(g.hMainWnd, 
                           IDC_EDITWND); 
 
    if ((g.hTreeWnd == FALSE) || (g.hLogWnd == FALSE)) 
    { 
        return FALSE; 
    } 
 
    ResizeWindows(FALSE, 0); 
 
    return TRUE; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// 
//  MainDlgProc() 
// 
////////////////////////////////////////////////////////////////////////////// 
LRESULT CALLBACK MainDlgProc (HWND   hWnd, 
                              UINT   uMsg, 
                              WPARAM wParam, 
                              LPARAM lParam) 
{ 
    static BOOL     bButtonDown = FALSE; 
     
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
            return TRUE; 
 
        case WM_COMMAND: 
        { 
            LRESULT lResult; 
             
            lResult = DoCommand(wParam, lParam); 
            return lResult; 
        } 
 
        // button and mousemove messages tracked to move 
        // the bar between the treeview control and the 
        // edit control 
        case WM_LBUTTONDOWN: 
        { 
            bButtonDown = TRUE; 
            SetCapture(hWnd); 
            return 0; 
        } 
 
        case WM_LBUTTONUP: 
        { 
            bButtonDown = FALSE; 
            ReleaseCapture(); 
            return 0; 
        } 
 
        case WM_MOUSEMOVE: 
        { 
            if (bButtonDown) 
            { 
                ResizeWindows(TRUE, (DWORD)LOWORD(lParam)); 
                return 1; 
            } 
            break; 
        } 
 
        case WM_SIZE: 
        { 
            ResizeWindows(FALSE, 0); 
            return 1; 
        } 
 
        // catch right click in tree view to make 
        // popup menu 
        case WM_NOTIFY: 
        { 
            LPNMHDR     pnmhdr; 
            POINT       pt; 
            HTREEITEM   hItem; 
            TV_HITTESTINFO  hittestinfo; 
            RECT        rc; 
 
            pnmhdr = (LPNMHDR)lParam; 
 
            // make sure it's a right click and it's in the treeview 
            if ((pnmhdr->code != NM_RCLICK) || (pnmhdr->hwndFrom != g.hTreeWnd)) 
            { 
                break; 
            } 
 
            GetCursorPos(&pt); 
            GetWindowRect(g.hTreeWnd, 
                          &rc); 
             
            hittestinfo.pt.x = pt.x - rc.left; 
            hittestinfo.pt.y = pt.y - rc.top; 
 
            // hittest to get the tree view item 
            hItem = TreeView_HitTest(g.hTreeWnd, 
                                     &hittestinfo); 
 
            // only display a menu if the mouse is actually 
            // over the item (TVHT_ONITEM) 
            if (hItem == NULL || (!(hittestinfo.flags & TVHT_ONITEM)) ) 
            { 
                return TRUE; 
            } 
 
            // select that item (right clicking will not select 
            // by default 
            TreeView_Select(g.hTreeWnd, 
                            hItem, 
                            TVGN_CARET); 
 
            // create the menu 
            DoPopupMenu(hItem, pt); 
 
            return TRUE; 
                            
             
        } 
         
        case WM_CLOSE: 
 
            // save the current window location 
            WriteToDisk(); 
            CleanUp(); 
            MySaveWindow(hWnd); 
            PostQuitMessage(0); 
            return 1; 
 
        default: 
            break; 
    } 
    return 0; 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// 
//  ResizeWindows - Handles resizing the two child windows of the 
//      main window.  If bSizeBar is true, then the sizing is happening 
//      because the user is moving the bar.  if bSizeBar is false, the sizing 
//      is happening because of the WM_SIZE or something like that. 
// 
//////////////////////////////////////////////////////////////////////////////// 
BOOL ResizeWindows(BOOL bSizeBar, DWORD dwBarLocation) 
{ 
    RECT            rc, rc2; 
    int             x; 
 
    // is the user moving the bar? 
    if (!bSizeBar) 
    { 
        dwBarLocation = g.dwBarLocation; 
    } 
 
    GetClientRect(g.hMainWnd, &rc); 
 
    // make sure the bar is in a OK location 
    if (bSizeBar) 
    { 
        if ((LONG)dwBarLocation < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) 
            return FALSE; 
 
        if ((LONG)(rc.right - dwBarLocation) < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) 
            return FALSE; 
    } 
 
    // save the bar location 
    g.dwBarLocation = dwBarLocation; 
 
    // get the size of the frame 
    x = GetSystemMetrics(SM_CXFRAME); 
 
    // move tree windows 
    MoveWindow(g.hTreeWnd, 
               0, 
               0, 
               dwBarLocation, 
               rc.bottom, 
               TRUE); 
 
    // get the size of the window (in case move window failed 
    GetClientRect(g.hTreeWnd, &rc2); 
 
    // move the edit window with respect to the tree window 
    MoveWindow(g.hLogWnd, 
               rc2.right-rc2.left+x+SIZEBAR, 
               0, 
               rc.right-(rc2.right-rc2.left)-x-SIZEBAR, 
               rc.bottom, 
               TRUE); 
 
    return TRUE; 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// 
//  MySetWindow - reads in the window placement from registry 
//  and sets the window and bar. 
// 
////////////////////////////////////////////////////////////////////////////// 
void MySetWindow(HWND hWnd, int nCmdShow) 
{ 
    WINDOWPLACEMENT     pwp; 
    HKEY                hKey; 
    DWORD               dwDataSize; 
    DWORD               dwDataType; 
    RECT                rc; 
 
    pwp.length = sizeof(WINDOWPLACEMENT); 
 
    // open the key and read in the WINDOWPLACEMENT structure 
    RegOpenKeyEx(HKEY_CURRENT_USER, 
                 gszACDSampleKey, 
                 0, 
                 KEY_ALL_ACCESS, 
                 &hKey); 
 
    dwDataSize = sizeof(pwp); 
     
    if ( RegQueryValueEx(hKey, 
                         gszPlacementValue, 
                         0, 
                         &dwDataType, 
                         (LPBYTE)&pwp, 
                         &dwDataSize) ) 
    { 
        // if it fails, default 
        ShowWindow(g.hMainWnd, nCmdShow); 
        GetWindowRect(g.hMainWnd, &rc); 
        g.dwBarLocation = (rc.right - rc.left) / 2; 
    } 
    else 
    { 
        // if it succeeds, set the window and bar 
        dwDataSize = sizeof(DWORD); 
         
        if (RegQueryValueEx(hKey, 
                            gszBarLocation, 
                            0, 
                            &dwDataType, 
                            (LPBYTE)&g.dwBarLocation, 
                            &dwDataSize)) 
        { 
            g.dwBarLocation = (pwp.rcNormalPosition.right - pwp.rcNormalPosition.left) / 2; 
        } 
 
        SetWindowPlacement(g.hMainWnd, &pwp); 
    } 
 
 
    RegCloseKey( hKey ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// 
//  MySaveWindow() - save the current window placement and bar 
// 
////////////////////////////////////////////////////////////////////////////// 
void MySaveWindow(HWND hWnd) 
{ 
    WINDOWPLACEMENT     pwp; 
    HKEY                hKey; 
    DWORD               dwDisposition; 
 
 
    pwp.length = sizeof(WINDOWPLACEMENT); 
 
    // get and save 
    GetWindowPlacement(hWnd, &pwp); 
 
    RegCreateKeyEx(HKEY_CURRENT_USER, 
                   gszACDSampleKey, 
                   0, 
                   TEXT(""), 
                   REG_OPTION_NON_VOLATILE, 
                   KEY_ALL_ACCESS, 
                   0, 
                   &hKey, 
                   &dwDisposition); 
 
    RegSetValueEx(hKey, 
                  gszPlacementValue, 
                  0, 
                  REG_BINARY, 
                  (LPBYTE)&pwp, 
                  sizeof(WINDOWPLACEMENT)); 
 
    RegSetValueEx(hKey, 
                  gszBarLocation, 
                  0, 
                  REG_DWORD, 
                  (LPBYTE)&g.dwBarLocation, 
                  sizeof(DWORD)); 
 
    RegCloseKey( hKey ); 
 
} 
 
  
////////////////////////////////////////////////////////////////////////////// 
// 
//  AddItemToTree 
// 
//    add a new leaf to the tree 
// 
////////////////////////////////////////////////////////////////////////////// 
HTREEITEM AddItemToTree(HTREEITEM hParent, 
                        LPTSTR lpszName, 
                        LPARAM lParam, 
                        HTREEITEM * phItem) 
{  
    TV_ITEM         tvi;  
    TV_INSERTSTRUCT tvins;  
    HTREEITEM       hti;  
  
    tvi.mask = TVIF_TEXT | TVIF_PARAM; 
  
    // Set the text of the item.  
    tvi.pszText = lpszName;  
    tvi.cchTextMax = lstrlen(lpszName) * sizeof(TCHAR); 
 
    // Save the pointer to the buffer 
    tvi.lParam = lParam; 
  
    tvins.item = tvi;  
    tvins.hInsertAfter = TVI_SORT; 
  
    // Set the parent item 
    tvins.hParent = hParent; 
     
    // Add the item to the tree-view control.  
    hti = (HTREEITEM) SendMessage(g.hTreeWnd, 
                                  TVM_INSERTITEM, 
                                  0,  
                                  (LPARAM) (LPTV_INSERTSTRUCT) &tvins); 
 
    // save hitem 
    if (phItem) 
    { 
        *phItem = hti; 
    } 
 
    // select the item so it has focus 
    TreeView_Select(g.hTreeWnd, 
                    hti, 
                    TVGN_CARET); 
  
    return hti; 
}  
 
////////////////////////////////////////////////////////////////////////////// 
// 
//  DoPopupMenu(HTREEITEM hItem, 
//              POINT pt) 
// 
//      hItem - item to create menu for 
//      pt - location of mouse so we can create menu where it is 
// 
//   creates a popup menu, depending on what kind of item is selected  
// 
////////////////////////////////////////////////////////////////////////////// 
BOOL DoPopupMenu(HTREEITEM hItem, POINT pt) 
{ 
 
    HMENU       hMenu; 
    TV_ITEM     tvi; 
    TCHAR       szNewGroup[]        = TEXT("&New Group..."); 
    TCHAR       szNewAgent[]        = TEXT("New &Agent..."); 
    TCHAR       szAddAgent[]        = TEXT("A&dd Agent..."); 
    TCHAR       szGroupProperties[] = TEXT("&Group Properties..."); 
    TCHAR       szAgentStatus[]     = TEXT("Agent Status..."); 
    TCHAR       szAddGroup[]        = TEXT("Add Group..."); 
    TCHAR       szAgentProperties[] = TEXT("Agent Properties..."); 
    TCHAR       szGroupDelete[]     = TEXT("Group Delete"); 
    TCHAR       szAgentDelete[]     = TEXT("Agent Delete"); 
    TCHAR       szSignIn[]          = TEXT("Agent Sign In"); 
    TCHAR       szSignOut[]         = TEXT("Agent Sign Out");     
 
    // get the selected item 
    g.hTreeItemWithMenu = hItem; 
 
    // create the menu 
    hMenu = CreatePopupMenu(); 
 
    // get the lParam, which is a pointer to the item 
    tvi.mask = TVIF_HANDLE | TVIF_PARAM; 
    tvi.hItem = hItem; 
 
    TreeView_GetItem(g.hTreeWnd, 
                     &tvi); 
 
    if (!tvi.lParam) 
    { 
        return TRUE; 
    } 
     
    switch (((PGROUP)tvi.lParam)->dwKey) 
    { 
        // root item 
        case GROUPROOTKEY: 
             
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_NEWGROUP, 
                       szNewGroup); 
            break; 
 
        // root item 
        case AGENTROOTKEY: 
             
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_NEWAGENT, 
                       szNewAgent); 
            break; 
        // group leaf 
        case GROUPKEY: 
             
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       (UINT)IDM_GROUPADDTOLIST, 
                       szAddAgent); 
             
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       (UINT)IDM_GROUPAGENTSTATUS, 
                       szAgentStatus); 
 
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_GROUPPROPERTIES, 
                       szGroupProperties); 
 
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_GROUPDELETE, 
                       szGroupDelete); 
 
            break; 
        // agent leaf     
        case AGENTKEY: 
 
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       (UINT)IDM_AGENTADDTOLIST, 
                       szAddGroup); 
             
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_AGENTPROPERTIES, 
                       szAgentProperties); 
 
            AppendMenu(hMenu, 
                       MF_ENABLED | MF_STRING, 
                       IDM_AGENTDELETE, 
                       szAgentDelete); 
 
            break; 
             
        default: 
            break; 
    } 
 
    // actually show menu 
    TrackPopupMenu(hMenu, 
                   TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, 
                   pt.x, 
                   pt.y, 
                   0, 
                   g.hMainWnd, 
                   NULL); 
     
    return TRUE; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  LRESULT DoCommand(WPARAM wParam, LPARAM lParam) 
//      handle WM_COMMAND messages for MainDlgProc 
// 
/////////////////////////////////////////////////////////////////////////////// 
LRESULT DoCommand(WPARAM wParam, LPARAM lParam) 
{ 
    switch (LOWORD(wParam)) 
    { 
        // New - create a new tree, so just init 
        // the items and return 
        case ID_FILE_NEW: 
            DoGroupView(); 
            return 1; 
 
        // Open - read in a file 
        case ID_FILE_OPEN: 
            ReadInFile(); 
            return 1; 
         
        case ID_FILE_EXIT: 
            // save the current window location 
            WriteToDisk(); 
            CleanUp(); 
            MySaveWindow(g.hMainWnd); 
            PostQuitMessage(0); 
            return 1; 
 
        // new group 
        case ID_EDIT_ADDGROUP: 
        case IDM_NEWGROUP: 
            DialogBox(g.hInstance, 
                      MAKEINTRESOURCE(IDD_ADD), 
                      g.hTreeWnd, 
                      AddGroupDlgProc); 
 
            return 1; 
 
        // new agent     
        case ID_EDIT_ADDAGENT: 
        case IDM_NEWAGENT: 
            DialogBox(g.hInstance, 
                      MAKEINTRESOURCE(IDD_ADDAGENT), 
                      g.hTreeWnd, 
                      AddAgentDlgProc); 
            return 1; 
 
        // properties 
        case IDM_GROUPPROPERTIES: 
            DialogBox(g.hInstance, 
                      MAKEINTRESOURCE(IDD_ADD), 
                      g.hMainWnd, 
                      ChangeGroupDlgProc); 
 
            return 1; 
 
        // properties             
        case IDM_AGENTPROPERTIES: 
            DialogBox(g.hInstance, 
                      MAKEINTRESOURCE(IDD_ADDAGENT), 
                      g.hMainWnd, 
                      ChangeAgentDlgProc); 
 
            return 1; 
 
        // delete             
        case IDM_GROUPDELETE:             
        case IDM_AGENTDELETE: 
        { 
            DeleteLeafAndStruct(g.hTreeItemWithMenu); 
             
            return 1; 
        } 
 
 
        // add to list 
        case IDM_GROUPADDTOLIST: 
            DialogBoxParam(g.hInstance, 
                           MAKEINTRESOURCE(IDD_ADDTOLIST), 
                           g.hMainWnd, 
                           GroupAddToListProc, 
                           TRUE); 
             
            return 1; 
                      
        // add to list 
        case IDM_AGENTADDTOLIST: 
            DialogBoxParam(g.hInstance, 
                           MAKEINTRESOURCE(IDD_ADDTOLIST), 
                           g.hMainWnd, 
                           AgentAddToListProc, 
                           FALSE); 
 
            return 1; 
 
        case ID_VIEW_GROUP: 
            DoGroupView(); 
            return 1; 
             
        case ID_VIEW_AGENT: 
            DoAgentView(); 
            return 1; 
 
        default: 
            break; 
             
    } 
 
    return 0; 
} 
 
///////////////////////////////////////////////////////////////////////////////////////////////////// 
// 
//  AddGroupDlgProc - Window proc for the add agent/group dialog box 
// 
///////////////////////////////////////////////////////////////////////////////////////////////////// 
BOOL CALLBACK AddGroupDlgProc(HWND   hWnd, 
                              UINT   uMsg, 
                              WPARAM wParam, 
                              LPARAM lParam) 
{ 
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            // set text appropriately 
            SetWindowText(hWnd, 
                          TEXT("Add Group")); 
 
            BuildLineList(GetDlgItem(hWnd, 
                                     IDC_LINECOMBO), 
                          0); 
 
            BuildAddressList(GetDlgItem(hWnd, 
                                        IDC_ADDRESSCOMBO), 
                             hWnd, 
                             0); 
                           
            // set focus on first control 
            SetFocus(GetDlgItem(hWnd, 
                                IDC_NAME)); 
 
            return 0; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDC_LINECOMBO: 
                { 
                    if (HIWORD(wParam) == CBN_SELENDOK) 
                    { 
                        // need to redo addresses 
                        BuildAddressList(GetDlgItem(hWnd, 
                                                    IDC_ADDRESSCOMBO), 
                                         hWnd, 
                                         0); 
 
                        return 1; 
                    } 
                     
                    return 0; 
                } 
                case IDOK: 
                { 
                    TCHAR       szName[128]; 
                    PGROUP      pGroup; 
                    DWORD       dwLine, dwAddress; 
                    int         item; 
 
                    // get info 
                    SendDlgItemMessage(hWnd, 
                                       IDC_NAME, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szName); 
 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LINECOMBO, 
                                              CB_GETCURSEL, 
                                              0, 
                                              0); 
                     
                    dwLine = (DWORD)SendDlgItemMessage(hWnd, 
                                                       IDC_LINECOMBO, 
                                                       CB_GETITEMDATA, 
                                                       item, 
                                                       0); 
 
                    dwAddress = (DWORD)SendDlgItemMessage(hWnd, 
                                                          IDC_ADDRESSCOMBO, 
                                                          CB_GETCURSEL, 
                                                          0, 
                                                          0); 
                     
                    // create a structure 
                    pGroup = AddGroup(szName, 
                                      dwLine, 
                                      dwAddress); 
 
                    if (!pGroup) 
                    { 
                        return 1; 
                    } 
 
                    if (g.bGroupView) 
                    { 
                        // add it to the tree 
                        AddItemToTree(g.hGroupParent, 
                                      pGroup->lpszName, 
                                      (LPARAM)pGroup, 
                                      &pGroup->hItem); 
                    } 
 
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                case IDCANCEL: 
                { 
                    EndDialog(hWnd, 0); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
 
            } 
 
    } 
 
    return 0; 
} 
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////// 
// 
//  AddAgentDlgProc - Window proc for the add agent/group dialog box 
// 
///////////////////////////////////////////////////////////////////////////////////////////////////// 
BOOL CALLBACK AddAgentDlgProc(HWND   hWnd, 
                              UINT   uMsg, 
                              WPARAM wParam, 
                              LPARAM lParam) 
{ 
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            BuildLineList(GetDlgItem(hWnd, 
                                     IDC_LINECOMBO), 
                          0); 
 
            // set focus on first control 
            SetFocus(GetDlgItem(hWnd, 
                                IDC_NAME)); 
 
            return 0; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDOK: 
                { 
                    TCHAR       szName[128]; 
                    TCHAR       szNumber[128]; 
                    PAGENT      pAgent; 
                    DWORD       dwLine; 
                    int         item; 
 
                    // get info 
                    SendDlgItemMessage(hWnd, 
                                       IDC_NAME, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szName); 
 
                    SendDlgItemMessage(hWnd, 
                                       IDC_DESTADDRESS, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szNumber); 
 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LINECOMBO, 
                                              CB_GETCURSEL, 
                                              0, 
                                              0); 
                     
                    dwLine = (DWORD)SendDlgItemMessage(hWnd, 
                                                       IDC_LINECOMBO, 
                                                       CB_GETITEMDATA, 
                                                       item, 
                                                       0); 
 
                    // create a structure 
                    pAgent = AddAgent(szName, 
                                      szNumber, 
                                      dwLine); 
 
                    if (!pAgent) 
                    { 
                        return 1; 
                    } 
 
 
                    if (!g.bGroupView) 
                    { 
                    // add it to the tree 
                        AddItemToTree(g.hAgentParent, 
                                      pAgent->lpszName, 
                                      (LPARAM)pAgent, 
                                      &pAgent->hItem); 
                    } 
 
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                case IDCANCEL: 
                { 
                    EndDialog(hWnd, 0); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
 
            } 
    } 
    return 0; 
} 
 
////////////////////////////////////////////////////////////////////////////////// 
// 
//  ChangeGroupDlgProc - Window proc for the change (properties) dialog box 
//     for agents/groups 
// 
////////////////////////////////////////////////////////////////////////////////// 
BOOL CALLBACK ChangeGroupDlgProc(HWND   hWnd, 
                                 UINT   uMsg, 
                                 WPARAM wParam, 
                                 LPARAM lParam) 
{ 
    static TV_ITEM      tvi; 
     
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            // set text appropriately 
            SetWindowText(hWnd, 
                          TEXT("Change Group")); 
 
            // get PGROUP and set edit controls 
            tvi.mask    = TVIF_HANDLE | TVIF_PARAM; 
            tvi.hItem   = g.hTreeItemWithMenu; 
 
            TreeView_GetItem(g.hTreeWnd, 
                             &tvi); 
 
            SendDlgItemMessage(hWnd, 
                               IDC_NAME, 
                               WM_SETTEXT, 
                               0, 
                               (LPARAM)((PGROUP)tvi.lParam)->lpszName); 
 
            BuildLineList(GetDlgItem(hWnd, 
                                     IDC_LINECOMBO), 
                          (((PGROUP)tvi.lParam)->dwDeviceID)); 
 
             
            BuildAddressList(GetDlgItem(hWnd, 
                                        IDC_ADDRESSCOMBO), 
                             hWnd, 
                             (((PGROUP)tvi.lParam)->dwAddress)); 
 
            SetFocus(GetDlgItem(hWnd, 
                                IDC_NAME)); 
 
            return 0; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDC_LINECOMBO: 
                { 
                    if (HIWORD(wParam) == CBN_SELENDOK) 
                    { 
                        // need to redo addresses 
                        BuildAddressList(GetDlgItem(hWnd, 
                                                    IDC_ADDRESSCOMBO), 
                                         hWnd, 
                                         0); 
 
                        return 1; 
                    } 
                     
                    return 0; 
                } 
                case IDOK: 
                { 
                    TCHAR       szName[128]; 
                    PGROUP      pGroup; 
 
                    // get info 
                    SendDlgItemMessage(hWnd, 
                                       IDC_NAME, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szName); 
 
                    // get struct 
                    pGroup = (PGROUP)tvi.lParam; 
 
                    /// get device and address 
                    pGroup->dwDeviceID = SendDlgItemMessage(hWnd, 
                                            IDC_LINECOMBO, 
                                            CB_GETCURSEL, 
                                            0, 
                                            0); 
 
                    pGroup->dwDeviceID = SendDlgItemMessage(hWnd, 
                                                            IDC_LINECOMBO, 
                                                            CB_GETITEMDATA, 
                                                            (WPARAM)pGroup->dwDeviceID, 
                                                            0); 
 
                    pGroup->dwAddress = SendDlgItemMessage(hWnd, 
                                                           IDC_ADDRESSCOMBO, 
                                                           CB_GETCURSEL, 
                                                           0, 
                                                           0); 
 
                    // save new info and free old info 
                    ACDFree(pGroup->lpszName); 
                    pGroup->lpszName = ACDAlloc((lstrlen(szName) + 1) * sizeof(TCHAR)); 
                    lstrcpy(pGroup->lpszName, szName); 
 
                    // update item name 
                    tvi.mask = TVIF_TEXT; 
                    tvi.pszText = szName; 
                    tvi.cchTextMax = lstrlen(szName) * sizeof(TCHAR); 
                    TreeView_SetItem(g.hTreeWnd, 
                                     &tvi); 
                     
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                case IDCANCEL: 
                { 
                    EndDialog(hWnd, 0); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
 
            } 
    } 
    return 0; 
} 
 
 
////////////////////////////////////////////////////////////////////////////////// 
// 
//  ChangeGroupDlgProc - Window proc for the change (properties) dialog box 
//     for agents/groups 
// 
////////////////////////////////////////////////////////////////////////////////// 
BOOL CALLBACK ChangeAgentDlgProc(HWND   hWnd, 
                                 UINT   uMsg, 
                                 WPARAM wParam, 
                                 LPARAM lParam) 
{ 
    static TV_ITEM      tvi; 
     
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            // set text appropriately 
            SetWindowText(hWnd, 
                          TEXT("Change Agent")); 
 
            // get PGROUP and set edit controls 
            tvi.mask    = TVIF_HANDLE | TVIF_PARAM; 
            tvi.hItem   = g.hTreeItemWithMenu; 
 
            TreeView_GetItem(g.hTreeWnd, 
                             &tvi); 
 
            SendDlgItemMessage(hWnd, 
                               IDC_NAME, 
                               WM_SETTEXT, 
                               0, 
                               (LPARAM)((PAGENT)tvi.lParam)->lpszName); 
 
            SendDlgItemMessage(hWnd, 
                               IDC_DESTADDRESS, 
                               WM_SETTEXT, 
                               0, 
                               (LPARAM)((PAGENT)tvi.lParam)->lpszNumber); 
 
            BuildLineList(GetDlgItem(hWnd, 
                                     IDC_LINECOMBO), 
                          (((PAGENT)tvi.lParam)->dwDeviceID)); 
 
            SetFocus(GetDlgItem(hWnd, 
                                IDC_NAME)); 
 
            return 0; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDOK: 
                { 
                    TCHAR       szName[128]; 
                    TCHAR       szNumber[128]; 
                    PAGENT      pAgent; 
 
                    // get info 
                    SendDlgItemMessage(hWnd, 
                                       IDC_NAME, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szName); 
 
                    SendDlgItemMessage(hWnd, 
                                       IDC_DESTADDRESS, 
                                       WM_GETTEXT, 
                                       128, 
                                       (LPARAM)szNumber); 
 
                    // get struct 
                    pAgent = (PAGENT)tvi.lParam; 
 
                    /// get device and address 
                    pAgent->dwDeviceID = SendDlgItemMessage(hWnd, 
                                            IDC_LINECOMBO, 
                                            CB_GETCURSEL, 
                                            0, 
                                            0); 
 
                    pAgent->dwDeviceID = SendDlgItemMessage(hWnd, 
                                                            IDC_LINECOMBO, 
                                                            CB_GETITEMDATA, 
                                                            (WPARAM)pAgent->dwDeviceID, 
                                                            0); 
 
                    // save new info and free old info 
                    ACDFree(pAgent->lpszName); 
                    pAgent->lpszName = ACDAlloc((lstrlen(szName) + 1) * sizeof(TCHAR)); 
                    lstrcpy(pAgent->lpszName, szName); 
 
 
                    ACDFree(pAgent->lpszNumber); 
                    pAgent->lpszNumber = ACDAlloc((lstrlen(szNumber) + 1) * sizeof(TCHAR)); 
                    lstrcpy(pAgent->lpszNumber, szNumber); 
 
                    // update item name 
                    tvi.mask = TVIF_TEXT; 
                    tvi.pszText = szName; 
                    tvi.cchTextMax = lstrlen(szName) * sizeof(TCHAR); 
                    TreeView_SetItem(g.hTreeWnd, 
                                     &tvi); 
                     
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                case IDCANCEL: 
                { 
                    EndDialog(hWnd, 0); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
 
            } 
    } 
    return 0; 
} 
 
////////////////////////////////////////////////////////////////////////////////////// 
// 
//  AddToList() - Window proc for Add Agent To Group and Add Group To Agent 
//    dialog box 
// 
////////////////////////////////////////////////////////////////////////////////////// 
BOOL CALLBACK GroupAddToListProc(HWND   hWnd, 
                                 UINT   uMsg, 
                                 WPARAM wParam, 
                                 LPARAM lParam) 
{ 
    static PGROUP           pGroup; 
    PAGENT                  pAgent; 
    PLISTITEM               pList; 
    TV_ITEM                 tvi; 
    DWORD                   dwListBox; 
    BOOL                    bFound; 
    int                     item; 
    TCHAR                   szBuffer[128]; 
     
     
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            // get the item in question 
            tvi.mask    = TVIF_HANDLE | TVIF_PARAM; 
            tvi.hItem   = g.hTreeItemWithMenu; 
 
            TreeView_GetItem(g.hTreeWnd, 
                             &tvi); 
 
            pGroup = (PGROUP)tvi.lParam; 
 
            // init lists 
            if (pGroup) 
            { 
                // initialize text in dialog 
                wsprintf(szBuffer, TEXT("Add To %s"), pGroup->lpszName); 
 
                SetWindowText(hWnd, 
                              TEXT("Add To Group")); 
 
                SetDlgItemText(hWnd, 
                               IDC_STATICNOTINLIST, 
                               TEXT("Not in Group")); 
                SetDlgItemText(hWnd, 
                               IDC_STATICINLIST, 
                               TEXT("Group Members")); 
 
                pAgent = g.pAgents; 
 
                // walk list and initialize list boxes 
                while (pAgent) 
                { 
                    pList = pGroup->pAgentList; 
 
                    bFound = FALSE; 
                 
                    while (pList) 
                    { 
                        if (pList->pAgent == pAgent) 
                        { 
                            bFound = TRUE; 
                            break; 
                        } 
 
                        pList = pList->pNext; 
                    } 
 
                    // if it was found, it is already a member of 
                    // the group 
                    if (bFound) 
                    { 
                        dwListBox = IDC_LIST2; 
                    } 
                    else 
                    { 
                        dwListBox = IDC_LIST1; 
                    } 
 
                    // add to correct list box 
                    item = SendDlgItemMessage(hWnd, 
                                              dwListBox, 
                                              LB_ADDSTRING, 
                                              0, 
                                              (LPARAM)pAgent->lpszName); 
 
                    // set the item data to be the item so we can get back it. 
                    if (item != LB_ERR) 
                    { 
                        SendDlgItemMessage(hWnd, 
                                           dwListBox, 
                                           LB_SETITEMDATA, 
                                           (WPARAM)item, 
                                           (LPARAM)pAgent); 
                    } 
 
                    pAgent = pAgent->pNext; 
                } 
            } 
 
             
             
            return 1; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDC_ADD: 
                { 
                    // get the item 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LIST1, 
                                              LB_GETCURSEL, 
                                              0, 
                                              0); 
 
                    if (item == 0) 
                    { 
                        if (!SendDlgItemMessage(hWnd, 
                                                IDC_LIST1, 
                                                LB_GETSEL, 
                                                (WPARAM)item, 
                                                0)) 
                        { 
                            item = -1; 
                        } 
                    } 
 
                    if (item != -1) 
                    { 
                        // get the PAGENT associated with it 
                        pAgent = (PAGENT)SendDlgItemMessage(hWnd, 
                                                            IDC_LIST1, 
                                                            LB_GETITEMDATA, 
                                                            (WPARAM)item, 
                                                            0); 
 
                        // delete it from this listbox 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST1, 
                                           LB_DELETESTRING, 
                                           (WPARAM)item, 
                                           0); 
 
                        // add it to this list box 
                        item = SendDlgItemMessage(hWnd, 
                                                  IDC_LIST2, 
                                                  LB_ADDSTRING, 
                                                  0, 
                                                  (LPARAM)pAgent->lpszName); 
 
                        // set the item data again 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST2, 
                                           LB_SETITEMDATA, 
                                           item, 
                                           (WPARAM)pAgent); 
 
                        // add it to the group's list 
                        InsertIntoGroupList(pGroup, 
                                            pAgent); 
                         
                        return 1; 
                         
                    } 
                } 
                break; 
                 
                case IDC_REMOVE: 
                { 
                    // get the item 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LIST2, 
                                              LB_GETCURSEL, 
                                              0, 
                                              0); 
 
                    if (item == 0) 
                    { 
                        if (!SendDlgItemMessage(hWnd, 
                                                IDC_LIST2, 
                                                LB_GETSEL, 
                                                (WPARAM)item, 
                                                0)) 
                        { 
                            item = -1; 
                        } 
                    } 
 
                    if (item != -1) 
                    { 
                        // get the struct associated with it 
                        pAgent = (PAGENT)SendDlgItemMessage(hWnd, 
                                                                IDC_LIST2, 
                                                                LB_GETITEMDATA, 
                                                                (WPARAM)item, 
                                                                0); 
 
                        // delete it from this list 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST2, 
                                           LB_DELETESTRING, 
                                           (WPARAM)item, 
                                           0); 
 
                        // add it to this list 
                        item = SendDlgItemMessage(hWnd, 
                                                  IDC_LIST1, 
                                                  LB_ADDSTRING, 
                                                  0, 
                                                  (LPARAM)pAgent->lpszName); 
 
                        // set the item data 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST1, 
                                           LB_SETITEMDATA, 
                                           item, 
                                           (WPARAM)pAgent); 
 
                        // remove it from the lists 
                        RemoveFromGroupList(pGroup, 
                                            pAgent); 
                         
                        return 1; 
                         
                    } 
                     
                } 
                break; 
 
 
                // bug idcancel doesn't cancel 
                case IDOK: 
                case IDCANCEL: 
                { 
                    UpdateGroupLeaf(pGroup); 
 
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
 
            } 
 
    } 
 
    return 0; 
} 
 
 
BOOL CALLBACK AgentAddToListProc(HWND   hWnd, 
                                 UINT   uMsg, 
                                 WPARAM wParam, 
                                 LPARAM lParam) 
{ 
    static PAGENT           pAgent; 
    PGROUP                  pGroup; 
    PLISTITEM               pList; 
    TV_ITEM                 tvi; 
    DWORD                   dwListBox; 
    BOOL                    bFound; 
    int                     item; 
    TCHAR                   szBuffer[128]; 
     
     
    switch (uMsg) 
    { 
        case WM_INITDIALOG: 
 
            // get the item in question 
            tvi.mask    = TVIF_HANDLE | TVIF_PARAM; 
            tvi.hItem   = g.hTreeItemWithMenu; 
 
            TreeView_GetItem(g.hTreeWnd, 
                             &tvi); 
 
            pAgent = (PAGENT)tvi.lParam; 
 
            // init lists 
            if (pAgent) 
            { 
                // initialize text in dialog 
                wsprintf(szBuffer, TEXT("Add To %s"), pAgent->lpszName); 
 
                SetWindowText(hWnd, 
                              TEXT("Add To Agent")); 
 
                SetDlgItemText(hWnd, 
                               IDC_STATICNOTINLIST, 
                               TEXT("Not Member Of")); 
                SetDlgItemText(hWnd, 
                               IDC_STATICINLIST, 
                               TEXT("Member Of")); 
 
                pGroup = g.pGroups; 
 
                // walk list and initialize list boxes 
                while (pGroup) 
                { 
                    pList = pGroup->pAgentList; 
 
                    bFound = FALSE; 
                 
                    while (pList) 
                    { 
                        if (pList->pAgent == pAgent) 
                        { 
                            bFound = TRUE; 
                            break; 
                        } 
 
                        pList = pList->pNext; 
                    } 
 
                    // if it was found, it is already a member of 
                    // the group 
                    if (bFound) 
                    { 
                        dwListBox = IDC_LIST2; 
                    } 
                    else 
                    { 
                        dwListBox = IDC_LIST1; 
                    } 
 
                    // add to correct list box 
                    item = SendDlgItemMessage(hWnd, 
                                              dwListBox, 
                                              LB_ADDSTRING, 
                                              0, 
                                              (LPARAM)pGroup->lpszName); 
 
                    // set the item data to be the item so we can get back it. 
                    if (item != LB_ERR) 
                    { 
                        SendDlgItemMessage(hWnd, 
                                           dwListBox, 
                                           LB_SETITEMDATA, 
                                           (WPARAM)item, 
                                           (LPARAM)pGroup); 
                    } 
 
                    pGroup = pGroup->pNext; 
                } 
            } 
 
             
             
            return 1; 
 
        case WM_COMMAND: 
 
            switch (LOWORD(wParam)) 
            { 
                case IDC_ADD: 
                { 
                    // get the item 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LIST1, 
                                              LB_GETCURSEL, 
                                              0, 
                                              0); 
 
                    if (item == 0) 
                    { 
                        if (!SendDlgItemMessage(hWnd, 
                                                IDC_LIST1, 
                                                LB_GETSEL, 
                                                (WPARAM)item, 
                                                0)) 
                        { 
                            item = -1; 
                        } 
                    } 
 
                    if (item != -1) 
                    { 
                        // get the PGROUP associated with it 
                        pGroup = (PGROUP)SendDlgItemMessage(hWnd, 
                                                                IDC_LIST1, 
                                                                LB_GETITEMDATA, 
                                                                (WPARAM)item, 
                                                                0); 
 
                        // delete it from this listbox 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST1, 
                                           LB_DELETESTRING, 
                                           (WPARAM)item, 
                                           0); 
 
                        // add it to this list box 
                        item = SendDlgItemMessage(hWnd, 
                                                  IDC_LIST2, 
                                                  LB_ADDSTRING, 
                                                  0, 
                                                  (LPARAM)pGroup->lpszName); 
 
                        // set the item data again 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST2, 
                                           LB_SETITEMDATA, 
                                           item, 
                                           (WPARAM)pGroup); 
 
                        // add it to the item's list 
                        InsertIntoGroupList(pGroup, 
                                            pAgent); 
                         
                        return 1; 
                         
                    } 
                } 
                break; 
                 
                case IDC_REMOVE: 
                { 
                    // get the item 
                    item = SendDlgItemMessage(hWnd, 
                                              IDC_LIST2, 
                                              LB_GETCURSEL, 
                                              0, 
                                              0); 
 
                    if (item == 0) 
                    { 
                        if (!SendDlgItemMessage(hWnd, 
                                                IDC_LIST2, 
                                                LB_GETSEL, 
                                                (WPARAM)item, 
                                                0)) 
                        { 
                            item = -1; 
                        } 
                    } 
 
                    if (item != -1) 
                    { 
                        // get the struct associated with it 
                        pGroup = (PGROUP)SendDlgItemMessage(hWnd, 
                                                                IDC_LIST2, 
                                                                LB_GETITEMDATA, 
                                                                (WPARAM)item, 
                                                                0); 
 
                        // delete it from this list 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST2, 
                                           LB_DELETESTRING, 
                                           (WPARAM)item, 
                                           0); 
 
                        // add it to this list 
                        item = SendDlgItemMessage(hWnd, 
                                                  IDC_LIST1, 
                                                  LB_ADDSTRING, 
                                                  0, 
                                                  (LPARAM)pGroup->lpszName); 
 
                        // set the item data 
                        SendDlgItemMessage(hWnd, 
                                           IDC_LIST1, 
                                           LB_SETITEMDATA, 
                                           item, 
                                           (WPARAM)pGroup); 
 
                        // remove it from the lists 
                        RemoveFromGroupList(pGroup, 
                                            pAgent); 
                         
                        return 1; 
                         
                    } 
                     
                } 
                break; 
 
 
                // bug idcancel doesn't cancel 
                case IDOK: 
                case IDCANCEL: 
                { 
                    EndDialog(hWnd, 1); 
                    return 1; 
                } 
 
                default: 
                    return 0; 
            } 
    } 
    return 0; 
} 
 
////////////////////////////////////////////////////////////// 
// 
//  BOOL DeleteLeafAndStruct(HTREEITEM hItem) 
//    delete hItem from the tree and deleted associated 
//    structure 
// 
////////////////////////////////////////////////////////////// 
BOOL DeleteLeafAndStruct(HTREEITEM hItem) 
{ 
    TV_ITEM     tvi; 
 
    // get the item 
    tvi.mask = TVIF_PARAM; 
    tvi.hItem = hItem; 
 
    TreeView_GetItem(g.hTreeWnd, 
                     &tvi); 
 
    // delete the structure 
    if (((PGENERICSTRUCT)tvi.lParam)->dwKey == GROUPKEY) 
    { 
        DeleteGroup((PGROUP)tvi.lParam); 
    } 
    else 
    { 
        DeleteAgent((PAGENT)tvi.lParam); 
    } 
 
    // remove it from the tree 
    TreeView_DeleteItem(g.hTreeWnd, 
                        hItem); 
 
    return TRUE; 
} 
 
 
//////////////////////////////////////////////////////////////////// 
// 
//  BOOL BuildLineList(HWND hWnd, 
//                     DWORD dwDeviceID) 
// 
//  Fill in ComboBox with names of all available TAPI 
//  devices 
// 
//////////////////////////////////////////////////////////////////// 
BOOL BuildLineList(HWND hWnd, 
                   DWORD dwDeviceID) 
{ 
    DWORD               dwDev; 
    LPLINEDEVCAPS       pLineDevCaps; 
    int                 item; 
    BOOL                bSet = FALSE; 
 
    // clear dropdown box 
    SendMessage(hWnd, 
                CB_RESETCONTENT, 
                0, 
                0); 
 
    // loop through all devices 
    for (dwDev = 0; dwDev < g.dwNumDevs; dwDev++) 
    { 
        pLineDevCaps = LineGetDevCaps(g.hLineApp, 
                                      dwDev); 
 
        // add the string to to list 
        if (pLineDevCaps == NULL || pLineDevCaps->dwLineNameSize == 0) 
        { 
            item = SendMessage(hWnd, 
                               CB_ADDSTRING, 
                               0, 
                               (LPARAM)TEXT("NoName")); 
        } 
        else 
        { 
            item = SendMessage(hWnd, 
                               CB_ADDSTRING, 
                               0, 
                               (LPARAM)((LPTSTR)((LPBYTE)pLineDevCaps + pLineDevCaps->dwLineNameOffset))); 
        } 
 
        // save the device ID 
        SendMessage(hWnd, 
                    CB_SETITEMDATA, 
                    item, 
                    dwDev); 
 
        // if this is the device we are looking for 
        // set it to be selected 
        if (dwDev == dwDeviceID) 
        { 
            SendMessage(hWnd, 
                        CB_SETCURSEL, 
                        (WPARAM)item, 
                        0); 
 
            bSet = TRUE; 
        } 
         
        if (pLineDevCaps != NULL) 
        { 
            ACDFree((HLOCAL)pLineDevCaps); 
        } 
    } 
 
    // if we didn't set the selection, default 
    if (!bSet) 
    { 
        SendMessage(hWnd, 
                    CB_SETCURSEL, 
                    0, 
                    0); 
    } 
 
    return TRUE; 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  BOOL BuildAddressList() 
// 
//  Fill combo box with list of addresses on selected device ID 
// 
/////////////////////////////////////////////////////////////////////////////// 
BOOL BuildAddressList(HWND hWnd, 
                      HWND hParentWnd, 
                      DWORD dwAddress) 
{ 
    TCHAR               szBuffer[32]; 
    LPLINEDEVCAPS       pLineDevCaps; 
    LPLINEADDRESSCAPS   pLineAddressCaps; 
    DWORD               dwCurAddress, dwDeviceID; 
    int                 iCurSel; 
 
    // clear box 
    SendMessage(hWnd, 
                CB_RESETCONTENT, 
                0, 
                0); 
 
    // get the current selected device 
    iCurSel = SendDlgItemMessage(hParentWnd, 
                                 IDC_LINECOMBO, 
                                 CB_GETCURSEL, 
                                 0, 
                                 0); 
 
    // get associated deviceid 
    dwDeviceID = (DWORD)SendDlgItemMessage(hParentWnd, 
                                           IDC_LINECOMBO, 
                                           CB_GETITEMDATA, 
                                           (WPARAM)iCurSel, 
                                           0); 
     
    pLineDevCaps = LineGetDevCaps(g.hLineApp, 
                                  dwDeviceID); 
    if (pLineDevCaps == NULL) 
      return FALSE; 
 
    // loop through all addresses 
    for (dwCurAddress = 0; dwCurAddress < pLineDevCaps->dwNumAddresses; dwCurAddress++) 
    { 
        pLineAddressCaps = LineGetAddressCaps(g.hLineApp, 
                                              dwDeviceID, 
                                              dwCurAddress); 
 
        // add name to list box 
        if (pLineAddressCaps == NULL || pLineAddressCaps->dwAddressSize == 0) 
        { 
            wsprintf(szBuffer, TEXT("Address %d"), dwCurAddress); 
             
            SendMessage(hWnd, 
                        CB_ADDSTRING, 
                        0, 
                        (LPARAM)szBuffer); 
        } 
        else 
        { 
            SendMessage(hWnd, 
                        CB_ADDSTRING, 
                        0, 
                        (LPARAM)((LPTSTR)((LPBYTE)pLineAddressCaps + pLineAddressCaps->dwAddressOffset))); 
        } 
         
        ACDFree((HLOCAL)pLineAddressCaps); 
    } 
 
    SendMessage(hWnd, 
                CB_SETCURSEL, 
                (WPARAM)dwAddress, 
                0); 
 
    ACDFree(pLineDevCaps); 
     
    return TRUE; 
} 
 
/////////////////////////////////////////////////////////////////////////// 
// 
//  BOOL UpdateGroupLeaf(PGROUP pStruct) 
// 
//  Updates a group in the tree view when a new agent is added to that 
//  group 
// 
/////////////////////////////////////////////////////////////////////////// 
BOOL UpdateGroupLeaf(PGROUP pStruct) 
{ 
    HTREEITEM   hItem; 
    PLISTITEM   pItem; 
    TV_ITEM     tvi; 
 
    // get the item's first child 
    hItem = TreeView_GetChild(g.hTreeWnd, 
                              pStruct->hItem); 
 
     
    while (hItem) 
    { 
        // delete all childre 
        TreeView_DeleteItem(g.hTreeWnd, 
                            hItem); 
        hItem = TreeView_GetChild(g.hTreeWnd, 
                                  pStruct->hItem); 
     
    } 
 
    pItem = pStruct->pAgentList; 
 
    // walk the agent list 
    while (pItem) 
    { 
        // add all the agents 
        hItem = AddItemToTree(pStruct->hItem, 
                              ((PAGENT)pItem->pAgent)->lpszName, 
                              (LPARAM)NULL, 
                              (HTREEITEM *)NULL); 
 
 
        // if currently logged into that group 
        /// bold that item 
        if (pItem->bLoggedIn) 
        { 
            tvi.mask = TVIF_STATE | TVIF_HANDLE; 
            tvi.hItem = hItem; 
            tvi.state = TVIS_BOLD; 
            tvi.stateMask = TVIS_BOLD; 
 
            TreeView_SetItem(g.hTreeWnd, 
                             &tvi); 
        } 
  
        pItem = pItem->pNext; 
    } 
 
     
    return TRUE; 
} 
 
 
/////////////////////////////////////////////////////////////////////// 
// 
//  BOOL DoGroupView() 
// 
//  Display the tree in a "group view" (show groups, and under the 
//  group, the agents that can log into that group) 
// 
/////////////////////////////////////////////////////////////////////// 
BOOL DoGroupView() 
{ 
    PGROUP      pGroupParent, pGroup; 
    TCHAR       szGroupParentName[] = TEXT("Groups"); 
    HTREEITEM   hItem; 
    TV_ITEM     tvi; 
 
    g.bGroupView = TRUE; 
 
    // get the root 
    hItem = TreeView_GetRoot(g.hTreeWnd); 
 
    // free resources allocated for root 
    if (hItem) 
    { 
        tvi.mask = TVIF_PARAM | TVIF_HANDLE; 
        tvi.hItem = hItem; 
        TreeView_GetItem(g.hTreeWnd, 
                         &tvi); 
 
        ACDFree((PAGENT)tvi.lParam); 
    } 
 
    // clear tree 
    TreeView_DeleteAllItems(g.hTreeWnd); 
 
    // alloc memory for the structure for the Group parent 
    pGroupParent = (PGROUP)ACDAlloc(sizeof(GROUP)); 
 
    // alloc memory and copy the fixed name 
    pGroupParent->lpszName = (LPTSTR)ACDAlloc((lstrlen(szGroupParentName) + 1) * sizeof(TCHAR)); 
    pGroupParent->dwKey = GROUPROOTKEY; 
     
    lstrcpy(pGroupParent->lpszName, szGroupParentName); 
 
    // add it to the tree 
    g.hGroupParent = AddItemToTree(TVI_ROOT, 
                                   pGroupParent->lpszName, 
                                   (LPARAM)pGroupParent, 
                                   &pGroupParent->hItem); 
 
    pGroup = g.pGroups; 
 
    // walk groups and add them to tree 
    while (pGroup) 
    { 
        AddItemToTree(g.hGroupParent, 
                      pGroup->lpszName, 
                      (LPARAM)pGroup, 
                      &pGroup->hItem); 
 
        UpdateGroupLeaf(pGroup); 
 
        pGroup = pGroup->pNext; 
    } 
     
    return TRUE; 
} 
 
 
//////////////////////////////////////////////////////////////////// 
// 
//  BOOL DoAgentView() 
// 
//  Displays the tree in an "agent view" 
// 
//////////////////////////////////////////////////////////////////// 
BOOL DoAgentView() 
{ 
    PAGENT      pAgentParent,pAgent; 
    TCHAR       szAgentParentName[] = TEXT("Agents"); 
    HTREEITEM   hItem; 
    TV_ITEM     tvi; 
 
    g.bGroupView = TRUE; 
 
    // get root, free resources 
    // and clear tree 
    hItem = TreeView_GetRoot(g.hTreeWnd); 
 
    if (hItem) 
    { 
        tvi.mask = TVIF_PARAM | TVIF_HANDLE; 
        tvi.hItem = hItem; 
        TreeView_GetItem(g.hTreeWnd, 
                         &tvi); 
 
        ACDFree((PGROUP)tvi.lParam); 
    } 
     
    TreeView_DeleteAllItems(g.hTreeWnd); 
 
    // alloc memory for the structure for the Agent parent 
    pAgentParent = (PAGENT)ACDAlloc(sizeof(AGENT)); 
 
    // alloc memory and copy the fixed name 
    pAgentParent->lpszName = (LPTSTR)ACDAlloc((lstrlen(szAgentParentName) + 1) * sizeof(TCHAR)); 
    pAgentParent->dwKey = GROUPROOTKEY; 
     
    lstrcpy(pAgentParent->lpszName, szAgentParentName); 
 
    // add it to the tree 
    g.hAgentParent = AddItemToTree(TVI_ROOT, 
                                   pAgentParent->lpszName, 
                                   (LPARAM)pAgentParent, 
                                   &pAgentParent->hItem); 
 
    pAgent = g.pAgents; 
 
    // walk agents and add all of them 
    while (pAgent) 
    { 
        AddItemToTree(g.hAgentParent, 
                      pAgent->lpszName, 
                      (LPARAM)pAgent, 
                      &pAgent->hItem); 
 
        pAgent = pAgent->pNext; 
    } 
     
    return TRUE; 
} 
 
////////////////////////////////////////////////////////////////////////////////////// 
// 
// FOLLOWING ARE ROUTINES TO SAVE AND RESTORE GROUP / AGENT INFORMATION 
// 
// An INI file has been used for this implementation. 
// 
// This format is used to make it easy for users to create an INI file that can be 
// read in 
// 
// However, a real implementation 
// may want to use the registry, or a private data file to store more detailed and/or 
// secure information 
// 
// 
 
#define SZGROUPS        TEXT("Groups") 
#define SZAGENTS        TEXT("Agents") 
#define SZGROUP         TEXT("GROUP") 
#define SZAGENT         TEXT("AGENT") 
#define SZINIFILE       TEXT("ACDSMPL.INI") 
#define SZGENERAL       TEXT("General") 
#define SZNUMAGENTS     TEXT("NumAgents") 
#define SZNUMGROUPS     TEXT("NumGroups") 
 
////////////////////////////////////////////////////////////////////////////// 
// 
//  void MakeAgentIndex(PAGENT * ppAgents) 
// 
//  creates an array of pagents 
// 
////////////////////////////////////////////////////////////////////////////// 
void MakeAgentIndex(PAGENT * ppAgents) 
{ 
    PAGENT pAgent; 
 
    pAgent = g.pAgents; 
     
    while (pAgent) 
    { 
        *ppAgents = pAgent; 
        pAgent = pAgent->pNext; 
        ppAgents++; 
    } 
                 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// int GetAgentIndex() 
// 
// retreives agent index 
// 
/////////////////////////////////////////////////////////////////////////////// 
int GetAgentIndex(PAGENT * ppAgents, 
                  PAGENT pAgent) 
{ 
    DWORD   dwCount; 
 
    for (dwCount = 0; dwCount < g.dwNumAgents; dwCount++) 
    { 
        if (ppAgents[dwCount] == pAgent) 
        { 
            return dwCount; 
        } 
    } 
 
    return -1; 
 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  BOOL WriteToDisk() 
// 
//  save current group/agent config to acdsmpl.ini 
// 
/////////////////////////////////////////////////////////////////////////////// 
BOOL WriteToDisk() 
{ 
    int         i; 
    PGROUP      pGroup; 
    PAGENT      pAgent; 
    PLISTITEM   pEntry; 
    TCHAR       szGroupName[32], szAgentName[32], szLineBuffer[512]; 
    PAGENT *    ppAgents; 
 
    // create an index of agents 
    ppAgents = (PAGENT *)ACDAlloc(sizeof(PAGENT) * g.dwNumAgents); 
    MakeAgentIndex(ppAgents); 
     
    pGroup = g.pGroups; 
 
    i = 0; 
 
    // walk groups 
    while (pGroup) 
    { 
        wsprintf(szGroupName, 
                 TEXT("%s%d"), 
                 SZGROUP, 
                 i); 
 
        wsprintf(szLineBuffer, 
                 TEXT("%s,%d,%d"), 
                 pGroup->lpszName, 
                 g.pdwPermIDs[pGroup->dwDeviceID], 
                 pGroup->dwAddress); 
 
        // add group to [groups] section 
        WritePrivateProfileString(SZGROUPS, 
                                  szGroupName, 
                                  szLineBuffer, 
                                  SZINIFILE); 
 
        pEntry = pGroup->pAgentList; 
 
        // walk agents in group 
        while (pEntry) 
        { 
            wsprintf(szAgentName, 
                     TEXT("%s%d"), 
                     SZAGENT, 
                     GetAgentIndex(ppAgents, 
                                   pEntry->pAgent)); 
 
            // write agent index to [groupx] section 
            WritePrivateProfileString(szGroupName, 
                                      szAgentName, 
                                      TEXT("1"), 
                                      SZINIFILE); 
 
            pEntry = pEntry->pNext; 
        } 
 
        pGroup = pGroup->pNext; 
 
        i++; 
    } 
 
    pAgent = g.pAgents; 
 
    i = 0; 
 
    //walk agents 
    while (pAgent) 
    { 
        wsprintf(szAgentName, 
                 TEXT("%s%d"), 
                 SZAGENT, 
                 i); 
 
        wsprintf(szLineBuffer, 
                 TEXT("%s,%s,%lu"), 
                 pAgent->lpszName, 
                 pAgent->lpszNumber, 
                 g.pdwPermIDs[pAgent->dwDeviceID]); 
 
        // write agent to [agents] section 
        WritePrivateProfileString(SZAGENTS, 
                                  szAgentName, 
                                  szLineBuffer, 
                                  SZINIFILE); 
 
        pAgent = pAgent->pNext; 
 
        i++; 
                  
    } 
 
    // save # of agents and groups 
    wsprintf(szLineBuffer, 
             TEXT("%lu"), 
             g.dwNumGroups); 
     
    WritePrivateProfileString(SZGENERAL, 
                              SZNUMGROUPS, 
                              szLineBuffer, 
                              SZINIFILE); 
     
    wsprintf(szLineBuffer, 
             TEXT("%lu"), 
             g.dwNumAgents); 
 
    WritePrivateProfileString(SZGENERAL, 
                              SZNUMAGENTS, 
                              szLineBuffer, 
                              SZINIFILE); 
 
    ACDFree(ppAgents); 
     
    return TRUE; 
} 
 
 
//////////////////////////////////////////////////////////////////////////////////// 
// 
//  BOOL ReadInFile() 
// 
//   Read in ACDSMPL.INI 
// 
//////////////////////////////////////////////////////////////////////////////////// 
BOOL ReadInFile() 
{ 
    TCHAR       szAgentLabel[32], 
                szGroupLabel[32]; 
    DWORD       dwID, dwAddress, dwNumAgents, dwNumGroups; 
    DWORD       dwCount, dwCount2; 
    PAGENT *    ppAgents = NULL; 
    LPTSTR      lpszName, lpszNumber, lpszDeviceID; 
    LPTSTR      lpszHold, szLineBuffer = NULL; 
    PGROUP      pGroup; 
     
    dwNumAgents = GetPrivateProfileInt(SZGENERAL, 
                                         SZNUMAGENTS, 
                                         0, 
                                         SZINIFILE); 
 
    dwNumGroups = GetPrivateProfileInt(SZGENERAL, 
                                         SZNUMGROUPS, 
                                         0, 
                                         SZINIFILE); 
 
    ppAgents = (PAGENT *)ACDAlloc(sizeof(PAGENT) * dwNumAgents); 
    szLineBuffer = (LPTSTR)ACDAlloc(512 * sizeof(WCHAR)); 
 
    if (!ppAgents || !szLineBuffer) 
    { 
        ACDFree(ppAgents); 
        ACDFree(szLineBuffer); 
        return FALSE; 
    } 
 
    lpszHold = szLineBuffer; 
 
    for (dwCount = 0; dwCount < dwNumAgents; dwCount++) 
    { 
        wsprintf(szAgentLabel, 
                 TEXT("%s%lu"), 
                 SZAGENT, 
                 dwCount); 
 
        GetPrivateProfileString(SZAGENTS, 
                                szAgentLabel, 
                                TEXT(""), 
                                szLineBuffer, 
                                512, 
                                SZINIFILE); 
 
        lpszName = (LPTSTR)szLineBuffer; 
         
        while (szLineBuffer && *szLineBuffer) 
        { 
            if (*szLineBuffer == TEXT(',')) 
            { 
                *szLineBuffer = TEXT('\0'); 
                szLineBuffer++; 
                break; 
            } 
 
            szLineBuffer++; 
        } 
 
        lpszNumber = (LPTSTR)szLineBuffer; 
         
        while (szLineBuffer && *szLineBuffer) 
        { 
            if (*szLineBuffer == TEXT(',')) 
            { 
                *szLineBuffer = TEXT('\0'); 
                szLineBuffer++; 
                dwID = _wtol(szLineBuffer); 
                dwID = GetDeviceID(dwID); 
                 
                ppAgents[dwCount] = AddAgent(lpszName, 
                                             lpszNumber, 
                                             dwID); 
 
                break; 
            } 
 
            szLineBuffer++; 
        } 
 
    } 
 
    for (dwCount = 0; dwCount < dwNumGroups; dwCount++) 
    { 
        wsprintf(szGroupLabel, 
                 TEXT("%s%lu"), 
                 SZGROUP, 
                 dwCount); 
 
        GetPrivateProfileString(SZGROUPS, 
                                szGroupLabel, 
                                TEXT(""), 
                                szLineBuffer, 
                                512, 
                                SZINIFILE); 
 
        lpszName = (LPTSTR)szLineBuffer; 
 
        while (szLineBuffer && *szLineBuffer) 
        { 
            if (*szLineBuffer == TEXT(',')) 
            { 
                *szLineBuffer = TEXT('\0'); 
                szLineBuffer++; 
                lpszDeviceID = szLineBuffer; 
                break; 
            } 
 
            szLineBuffer++; 
        } 
 
        while (szLineBuffer && *szLineBuffer) 
        { 
            if (*szLineBuffer == TEXT(',')) 
            { 
                *szLineBuffer = TEXT('\0'); 
                szLineBuffer++; 
 
                dwAddress = _wtol(szLineBuffer); 
 
                break; 
            } 
 
            szLineBuffer++; 
        } 
 
        dwID = _wtol(lpszDeviceID); 
        dwID = GetDeviceID(dwID); 
 
 
        pGroup = AddGroup(lpszName, 
                          dwID, 
                          dwAddress); 
 
        if (!pGroup) 
        { 
            continue; 
        } 
         
        for (dwCount2 = 0; dwCount2 < dwNumAgents; dwCount2++) 
        { 
            wsprintf(szAgentLabel, 
                     TEXT("%s%lu"), 
                     SZAGENT, 
                     dwCount2); 
             
            if (GetPrivateProfileString(szGroupLabel, 
                                        szAgentLabel, 
                                        TEXT(""), 
                                        szLineBuffer, 
                                        512, 
                                        SZINIFILE) != 0) 
            { 
                InsertIntoGroupList(pGroup, 
                                    ppAgents[dwCount2]); 
            } 
             
        }  // for dwcount2 
 
    }  // for dwcount 
 
    ACDFree(ppAgents); 
    ACDFree(lpszHold); 
 
    DoGroupView(); 
     
    return TRUE; 
}