/*---------------------------------------------------------------------------*\
| WINCHAT APPLICATION MODULE
|   This is the main module file for the application.  The application was
|   originally written by ClausGi for the Windows-For-WorkGroup product.
|   In the port to NT, all references to PEN-awareness and Protocol were
|   removed.  Extensive cleanup and documenting was also added in the port.
|
|   FUNCTIONS
|   ---------
|   myatol
|   UpdateButtonStates
|   appGetComputerName
|   AdjustEditWindows
|
|
| Copyright (c) Microsoft Corp., 1990-1993
|
| created: 01-Nov-91
| history: 01-Nov-91 <clausgi>  created.
|          29-Dec-92 <chriswil> port to NT, cleanup.
|          19-Oct-93 <chriswil> unicode enhancements from a-dianeo.
|
\*---------------------------------------------------------------------------*/

#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <ddeml.h>
#include <commdlg.h>
#include <commctrl.h>
#include <shellapi.h>
#include <nddeapi.h>
#include <richedit.h>
#include "winchat.h"
#include "dialogs.h"
#include "globals.h"
#include "nddeagnt.h"

#include <imm.h>
#include <htmlhelp.h>

#define ASSERT(x)

// This is used in the port to NT.  Since NT doesn't haven a dialogbox for
// this function, we'll use the lanman export.
//
#ifdef WIN32
#define FOCUSDLG_DOMAINS_ONLY        (1)
#define FOCUSDLG_SERVERS_ONLY        (2)
#define FOCUSDLG_SERVERS_AND_DOMAINS (3)

#define FOCUSDLG_BROWSE_LOGON_DOMAIN         0x00010000
#define FOCUSDLG_BROWSE_WKSTA_DOMAIN         0x00020000
#define FOCUSDLG_BROWSE_OTHER_DOMAINS        0x00040000
#define FOCUSDLG_BROWSE_TRUSTING_DOMAINS     0x00080000
#define FOCUSDLG_BROWSE_WORKGROUP_DOMAINS    0x00100000

#define FOCUSDLG_BROWSE_LM2X_DOMAINS         (FOCUSDLG_BROWSE_LOGON_DOMAIN | FOCUSDLG_BROWSE_WKSTA_DOMAIN | FOCUSDLG_BROWSE_OTHER_DOMAINS)
#define FOCUSDLG_BROWSE_ALL_DOMAINS          (FOCUSDLG_BROWSE_LOCAL_DOMAINS | FOCUSDLG_BROWSE_WORKGROUP_DOMAINS)
#define FOCUSDLG_BROWSE_LOCAL_DOMAINS        (FOCUSDLG_BROWSE_LM2X_DOMAINS | FOCUSDLG_BROWSE_TRUSTING_DOMAINS)

#define MY_LOGONTYPE                         (FOCUSDLG_BROWSE_ALL_DOMAINS | FOCUSDLG_SERVERS_ONLY)

UINT APIENTRY I_SystemFocusDialog(HWND,UINT,LPWSTR,UINT,PBOOL,LPWSTR,DWORD);
#endif

BOOL TranslateWideCharPosToMultiBytePos(HWND,DWORD,DWORD,LPDWORD,LPDWORD);


/*---------------------------------------------------------------------------*\
| WINDOWS MAIN
|   This is the main event-processing loop for the application.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;


    msg.wParam = 0;

    if(InitApplication(hInstance))
    {
        if(InitInstance(hInstance,nCmdShow))
        {
            while(GetMessage(&msg,NULL,0,0))
            {
                if(!TranslateAccelerator(hwndApp,hAccel,&msg))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }

            if(hszConvPartner)
                DdeFreeStringHandle(idInst,hszConvPartner);

            DdeFreeStringHandle(idInst,hszChatTopic);
            DdeFreeStringHandle(idInst,hszChatShare);
            DdeFreeStringHandle(idInst,hszLocalName );
            DdeFreeStringHandle(idInst,hszTextItem);
            DdeFreeStringHandle(idInst,hszConnectTest);
            DdeUninitialize(idInst);

            EndIniMapping();
        }
    }

    return((int)msg.wParam);
}


#ifdef WIN16
#pragma alloc_text ( _INIT, InitApplication )
#endif
/*---------------------------------------------------------------------------*\
| INITIALIZE APPLICATION
|   This routine registers the application with user.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
BOOL FAR InitApplication(HINSTANCE hInstance)
{
    WNDCLASS wc;


    wc.style         = 0;
    wc.lpfnWndProc   = MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(hInstance, TEXT("PHONE1"));
    wc.hCursor       = LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszMenuName  = szWinChatMenu;
    wc.lpszClassName = szWinChatClass;

    return(RegisterClass(&wc));
}


#define IMMMODULENAME L"IMM32.DLL"
#define PATHDLM     L'\\'
#define IMMMODULENAMELEN    ((sizeof PATHDLM + sizeof IMMMODULENAME) / sizeof(WCHAR))

VOID GetImmFileName(PWSTR wszImmFile)
{
    UINT i = GetSystemDirectoryW(wszImmFile, MAX_PATH);
    if (i > 0 && i < MAX_PATH - IMMMODULENAMELEN) {
        wszImmFile += i;
        if (wszImmFile[-1] != PATHDLM) {
            *wszImmFile++ = PATHDLM;
        }
    }
    StringCchCopyW(wszImmFile, MAX_PATH, IMMMODULENAME);
}

/*---------------------------------------------------------------------------*\
| IsTSRemoteSession
|
| Input:      None
| Output:     BOOL - TRUE if in a Terminal Server remote session (SessionId != 0)
|             FALSE - if error OR not in a TS rermote session
| Function:   To determine whether we are running in a TS remote session or not.
|
\*---------------------------------------------------------------------------*/
BOOL IsTSRemoteSession()
{
    BOOL      bRetVal;
    DWORD     dwSessionID;
    HINSTANCE hInst;
    FARPROC   lpfnProcessIdToSessionId;

    //assume failure
    bRetVal = FALSE;

    // load library and get proc address
    hInst=LoadLibrary(TEXT("kernel32.dll"));

    if (hInst)
    {
        lpfnProcessIdToSessionId = GetProcAddress(hInst,"ProcessIdToSessionId");

        if (lpfnProcessIdToSessionId )
        {
            if (lpfnProcessIdToSessionId(GetCurrentProcessId(),&dwSessionID))
            {
                if(dwSessionID!=0)
                {
                    bRetVal = TRUE;
                }
            }
        }

        // free the library
        FreeLibrary(hInst);
    }

    return bRetVal;
}




#ifdef WIN16
#pragma alloc_text ( _INIT, InitInstance )
#endif
/*---------------------------------------------------------------------------*\
| INITIALIZE APPLICATION INTSTANCE
|   This routine initializes instance information.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
BOOL FAR InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND      hwnd;
    HMENU     hMenu;
        HINSTANCE hmodNetDriver;
    int       cAppQueue;
    BOOL      bRet;

    hInst = hInstance;


    //
    // get DBCS flag
    //
    gfDbcsEnabled = GetSystemMetrics(SM_DBCSENABLED);

    if (GetSystemMetrics(SM_IMMENABLED)) {
        //
        // if IME is enabled, get real API addresses
        //
        WCHAR wszImmFile[MAX_PATH];
        HINSTANCE hInstImm32;
        GetImmFileName(wszImmFile);
        hInstImm32 = GetModuleHandle(wszImmFile);
        if (hInstImm32) {
            pfnImmGetContext = (PVOID)GetProcAddress(hInstImm32, "ImmGetContext");
            ASSERT(pfnImmGetContext);
            pfnImmReleaseContext = (PVOID)GetProcAddress(hInstImm32, "ImmReleaseContext");
            ASSERT(pfnImmReleaseContext);
            pfnImmGetCompositionStringW = (PVOID)GetProcAddress(hInstImm32, "ImmGetCompositionStringW");
            ASSERT(pfnImmGetCompositionStringW);
        }
    }

    // increase our app queue for better performance...
    //
    for(cAppQueue=128; !SETMESSAGEQUEUE(cAppQueue); cAppQueue >>= 1);


    //
    //
    bRet = FALSE;
    if(cAppQueue >= 8)
    {
        bRet = TRUE;

        cxIcon = GetSystemMetrics(SM_CXICON);
        cyIcon = GetSystemMetrics(SM_CYICON);
        hAccel = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDACCELERATORS));



        LoadIntlStrings();
        StartIniMapping();


        InitFontFromIni();


        // check if it's a Terminal Server remote session
        if (IsTSRemoteSession())
        {
            TCHAR szTSNotSupported[SZBUFSIZ];

            LoadString(hInst, IDS_TSNOTSUPPORTED, szTSNotSupported, SZBUFSIZ);

            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL, szTSNotSupported, szAppName, MB_OK | MB_ICONSTOP);
            return(FALSE);
        }

        // get our machine name and map to correct character set.
        //
        if(!appGetComputerName(szLocalName))
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }


        // initialize DDEML.
        //
        if(DdeInitialize(&idInst,(PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback,hInst),APPCLASS_STANDARD,0L))
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }


        ChatState.fMinimized  = (nCmdShow == SW_MINIMIZE) ? TRUE : FALSE;
        ChatState.fMMSound    = waveOutGetNumDevs();
        ChatState.fSound      = GetPrivateProfileInt(szPref,szSnd  ,1,szIni);
        ChatState.fToolBar    = GetPrivateProfileInt(szPref,szTool ,1,szIni);
        ChatState.fStatusBar  = GetPrivateProfileInt(szPref,szStat ,1,szIni);
        ChatState.fTopMost    = GetPrivateProfileInt(szPref,szTop  ,0,szIni);
        ChatState.fSideBySide = GetPrivateProfileInt(szPref,szSbS  ,0,szIni);
        ChatState.fUseOwnFont = GetPrivateProfileInt(szPref,szUseOF,0,szIni);

        hszLocalName          = DdeCreateStringHandle(idInst,szLocalName  ,0);
        hszChatTopic          = DdeCreateStringHandle(idInst,szChatTopic  ,0);
        hszChatShare          = DdeCreateStringHandle(idInst,szChatShare  ,0);
        hszServiceName        = DdeCreateStringHandle(idInst,szServiceName,0);
        hszConnectTest        = DdeCreateStringHandle(idInst,szConnectTest,0);
        hszTextItem           = DdeCreateStringHandle(idInst,szChatText   ,0);

        if(!hszLocalName || !hszChatTopic || !hszServiceName || !hszTextItem || !hszChatShare)
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }

        DdeNameService(idInst,hszServiceName,(HSZ)0,DNS_REGISTER);


        if(DdeGetLastError(idInst) != DMLERR_NO_ERROR)
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox (NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }

        cf_chatdata = RegisterClipboardFormat(TEXT("Chat Data"));
        if(!(cf_chatdata))
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }


        // get winnet extension browse dialog entry point
        //
        WNetServerBrowseDialog = NULL;
        hmodNetDriver          = WNETGETCAPS(0xFFFF);

        if(hmodNetDriver != NULL)
            WNetServerBrowseDialog = (WNETCALL)GetProcAddress(hmodNetDriver,(LPSTR)146);



        // create main window
        hwnd = CreateWindow(
            szWinChatClass,
            szAppName,
            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInstance,
            NULL
        );

        if(!hwnd)
        {
            MessageBeep(MB_ICONSTOP);
            MessageBox(NULL,szSysErr,szAppName,MB_OK | MB_ICONSTOP);
            return(FALSE);
        }

        hwndApp = hwnd; // save global

        // font choice struct init
        //
        chf.lStructSize    = sizeof(CHOOSEFONT);
        chf.lpLogFont      = &lfSnd;
        chf.Flags          = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
        chf.rgbColors      = GetSysColor(COLOR_WINDOWTEXT);
        chf.lCustData      = 0L;
        chf.lpfnHook       = NULL;
        chf.lpTemplateName = NULL;
        chf.hInstance      = NULL;
        chf.lpszStyle      = NULL;
        chf.nFontType      = SCREEN_FONTTYPE;
        chf.nSizeMin       = 0;
        chf.nSizeMax       = 0;


        // color choice init
        //
        chc.lStructSize    = sizeof(CHOOSECOLOR);
        chc.hwndOwner      = hwndApp;
        chc.hInstance      = hInst;
        chc.lpCustColors   = (LPDWORD)CustColors;
        chc.Flags          = CC_RGBINIT | CC_PREVENTFULLOPEN;
        chc.lCustData      = 0;
        chc.lpfnHook       = NULL;
        chc.lpTemplateName = NULL;


        // window placement...
        //
        if(ReadWindowPlacement(&Wpl))
        {
            // override these - CODEWORK don't need to save
            // them to .ini, but will mis-parse old .ini files
            // if change is made.
            //
            Wpl.showCmd         = nCmdShow;
            Wpl.ptMaxPosition.x = -1;
            Wpl.ptMaxPosition.y = -1;
            Wpl.flags           = 0;

            SetWindowPlacement(hwnd,&Wpl);
            UpdateWindow(hwnd);
        }
        else
            ShowWindow(hwnd,nCmdShow);

        //
        //
        hMenu = GetSystemMenu(hwnd,FALSE);
        AppendMenu(hMenu,MF_SEPARATOR,0,NULL);

        if(ChatState.fTopMost)
            AppendMenu(hMenu,MF_ENABLED | MF_CHECKED | MF_STRING,IDM_TOPMOST,szAlwaysOnTop);
        else
            AppendMenu(hMenu,MF_ENABLED | MF_UNCHECKED | MF_STRING,IDM_TOPMOST,szAlwaysOnTop);


        // Set topmost style...
        //
        SetWindowPos(hwndApp,ChatState.fTopMost ? HWND_TOPMOST : HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

        UpdateButtonStates();

#if !defined(_WIN64)

        {
            static NDDESHAREINFO nddeShareInfo = {
                1,              // revision
                szChatShare,
                SHARE_TYPE_STATIC,
                TEXT("WinChat|Chat\0\0"),
                TRUE,           // shared
                FALSE,          // not a service
                TRUE,           // can be started
                SW_SHOWNORMAL,
                {0,0},          // mod id
                0,              // no item list
                TEXT("")
            };

            TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 3] = TEXT("\\\\");
            DWORD cbName = MAX_COMPUTERNAME_LENGTH + 1;

            //
            // Make sure NetDDE DSDM has trusted shares set up properly for us.
            // This fix allows us to work with floating profiles.
            //

            START_NETDDE_SERVICES(hwnd);
            GetComputerName(&szComputerName[2],&cbName);
            NDdeShareAdd(szComputerName,2,NULL,(LPBYTE)&nddeShareInfo,sizeof(NDDESHAREINFO));
            NDdeSetTrustedShare(szComputerName, szChatShare,
                    NDDE_TRUST_SHARE_START | NDDE_TRUST_SHARE_INIT);
        }

#endif

    }

    return(bRet);
}


/*---------------------------------------------------------------------------*\
| MAIN WINDOW PROC
|   This is the main event-handler for the application.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT  lResult;


    lResult = 0l;
    switch(message)
    {
        case WM_CREATE:
            appWMCreateProc(hwnd);
            break;

        case WM_WININICHANGE:
            appWMWinIniChangeProc(hwnd);
            break;

        case WM_ERASEBKGND:
            if((lResult = (LRESULT)appWMEraseBkGndProc(hwnd)) == 0)
                lResult = DefWindowProc(hwnd,message,wParam,lParam);
            break;

        case WM_SETFOCUS:
            appWMSetFocusProc(hwnd);
            break;

        case WM_MENUSELECT:
            appWMMenuSelectProc(hwnd,wParam,lParam);
            break;

        case WM_TIMER:
            appWMTimerProc(hwnd);
            break;

        case WM_PAINT:
            appWMPaintProc(hwnd);
            break;

        case WM_QUERYDRAGICON:
            lResult = (LRESULT)(LPVOID)appWMQueryDragIconProc(hwnd);
            break;

        case WM_SIZE:
            appWMSizeProc(hwnd,wParam,lParam);
            break;

        case WM_INITMENU:
            appWMInitMenuProc((HMENU)wParam);
            break;

        case WM_SYSCOMMAND:
            if(!appWMSysCommandProc(hwnd,wParam,lParam))
                lResult = DefWindowProc(hwnd,message,wParam,lParam);
            break;

        case WM_COMMAND:
            if(!appWMCommandProc(hwnd,wParam,lParam))
                lResult = DefWindowProc(hwnd,message,wParam,lParam);
            break;

        case WM_NOTIFY:
            {
            LPTOOLTIPTEXT lpTTT = (LPTOOLTIPTEXT) lParam;

            if (lpTTT->hdr.code == TTN_NEEDTEXT) {
                LoadString (hInst, (UINT)(MH_BASE + lpTTT->hdr.idFrom), lpTTT->szText, 80);
                return TRUE;
            }
            }
            break;

#ifdef WIN32
        case WM_CTLCOLOREDIT:
        case WM_CTLCOLORSTATIC:
#else
        case WM_CTLCOLOR:
#endif
            if((lResult = (LRESULT)(LPVOID)appWMCtlColorProc(hwnd,wParam,lParam)) == 0l)
                lResult = DefWindowProc(hwnd,message,wParam,lParam);
            break;

        case WM_DESTROY:
            appWMDestroyProc(hwnd);
            break;

        case WM_CLOSE:
            WinHelp(hwnd,(LPTSTR)szHelpFile,HELP_QUIT,0L);

            // Fall through for final close.
            //


        default:
            lResult = DefWindowProc(hwnd,message,wParam,lParam);
            break;
    }

    return(lResult);
}


/*---------------------------------------------------------------------------*\
| EDIT-HOOK PROCEDURE
|   This is the main event-handler for the edit-control hook.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
LRESULT CALLBACK EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    WPARAM wSet;
    LPARAM lSet;
    GETTEXTLENGTHEX gettextlengthex;
    LRESULT lResult;
    LPTSTR lpszText;
    HANDLE hText;
    INT count;
    LPTSTR lpszStartSel;
    DWORD dwTemp1;
    DWORD dwTemp2;

    switch(msg) {
    case WM_IME_COMPOSITION:
        {
            LPWSTR  lpStrParam;
            LPSTR   lpStrTmp;
            HANDLE  hTmp;

            if (lParam & GCS_RESULTSTR)
            {
                HIMC  hImc;
                ULONG cCharsMbcs, cChars;

                //
                // Get input context of hwnd
                //

                if ((hImc = pfnImmGetContext(hwnd)) == 0)
                    break;

                //
                //ImmGetComposition returns the size of buffer needed in byte
                //

                cCharsMbcs =  pfnImmGetCompositionStringW(hImc,GCS_RESULTSTR, NULL , 0);
                if(!(cCharsMbcs))
                {
                    pfnImmReleaseContext(hwnd, hImc);
                    break;
                }

                lpStrParam = (LPWSTR)GlobalAlloc(GPTR,//HEAP_ZERO_MEMORY,
                                    cCharsMbcs + sizeof(WCHAR));

                if (lpStrParam==NULL)
                {
                    pfnImmReleaseContext(hwnd, hImc);
                    break;
                }

                pfnImmGetCompositionStringW(hImc, GCS_RESULTSTR, lpStrParam,
                                    cCharsMbcs);

                //
                // Compute character count including NULL char.
                //

                cChars = wcslen(lpStrParam) + 1;

                //
                // Set ChatData packet
                //

                ChatData.type                = CHT_DBCS_STRING;

                //
                // Get current cursor position
                //
                // !!! BUG BUG BUG !!!
                //
                //  This position data is only nice for Unicode Edit control.
                // is the partner has not Unicode Edit control. the string
                // will be truncated.
                //

                SendMessage(hwndSnd,EM_GETSEL,(WPARAM)&dwTemp1,(LPARAM)&dwTemp2);
                ChatData.uval.cd_dbcs.SelPos = MAKELONG((WORD)dwTemp1, (WORD)dwTemp2 );

                if (gfDbcsEnabled) {
                    //
                    // since text is passed as multi byte character string,
                    // position fixup is needed if DBCS is enabled
                    //
                    DWORD dwStart, dwEnd;

                    TranslateWideCharPosToMultiBytePos( hwndSnd,
                        (DWORD)LOWORD(ChatData.uval.cd_dbcs.SelPos),
                        (DWORD)HIWORD(ChatData.uval.cd_dbcs.SelPos),
                        &dwStart, &dwEnd );
                    ChatData.uval.cd_dbcs.SelPos
                        = MAKELONG((WORD)dwStart, (WORD)dwEnd );
               }

               //
               // Allocate string buffer for DDE.
               //

               if((hTmp = GlobalAlloc( GMEM_ZEROINIT |
                                       GMEM_MOVEABLE |
                                       GMEM_DDESHARE   ,
                                       (DWORD)cCharsMbcs)) == NULL)
               {
                    pfnImmReleaseContext(hwnd, hImc);
                    GlobalFree(lpStrParam);
                    break;
               }

               lpStrTmp                     = GlobalLock(hTmp);

               //
               // Store MBCS string into DDE buffer.
               //
               // In CHT_DBCS_STRING context, we should send mbcs string
               // for downlevel connectivity.
               //

               WideCharToMultiByte(CP_ACP,0,lpStrParam,cChars/* + 1*/,
                                            lpStrTmp  ,cCharsMbcs/* + 1*/,
                                            NULL,NULL);

               //
               // Keep the buffer handle in to DDE message packet.
               //

               GlobalUnlock(hTmp);
               ChatData.uval.cd_dbcs.hString = hTmp;

               //
               // Now, we have a packet to send server/client, just send it.
               //

               wSet = SET_EN_NOTIFY_WPARAM(ID_EDITSND,EN_DBCS_STRING,hwnd);
               lSet = SET_EN_NOTIFY_LPARAM(ID_EDITSND,EN_DBCS_STRING,hwnd);
               SendMessage(hwndApp,WM_COMMAND,wSet,lSet);

               //
               // if we have still a connection to server/client. repaint text.
               //

               if(ChatState.fConnected)
                   SendMessage(hwndSnd,EM_REPLACESEL,0,(LPARAM)lpStrParam);

               pfnImmReleaseContext(hwnd, hImc);
               GlobalFree(lpStrParam);

               return(TRUE);
            }
            break;
        }

    case WM_KEYDOWN:
        if (wParam == VK_DELETE) {
            DWORD dwLastError;
            ChatData.type                = CHT_CHAR;

            SendMessage(hwndSnd,EM_GETSEL,(WPARAM)&dwTemp1,(LPARAM)&dwTemp2);
            ChatData.uval.cd_dbcs.SelPos = MAKELONG((WORD)dwTemp1, (WORD)dwTemp2 );

            lResult=SendMessage(hwndSnd,WM_GETTEXTLENGTH,0,0);
            // if we are trying to delete at the end of the line then ignore it
            if(lResult<=LOWORD(ChatData.uval.cd_char.SelPos)) break;

            if (LOWORD(ChatData.uval.cd_char.SelPos) == HIWORD(ChatData.uval.cd_char.SelPos)) {

                // get handle to the text
                hText = (HANDLE)SendMessage( hwndSnd, EM_GETHANDLE, 0, 0);
                if( !(hText) )
                    break;

                lpszText = LocalLock( hText);
                if( !(lpszText))
                {
                    LocalUnlock(hText);
                    break;
                }
                lpszStartSel=lpszText;
                for(count=0;count<LOWORD(ChatData.uval.cd_char.SelPos);count++)
                {
                    lpszStartSel=CharNext(lpszStartSel);
                    if(lpszStartSel[0] == TEXT('\0')) break;  // if at the end then break since something is mesed
                }

                if(lpszStartSel[0] != TEXT('\0') && lpszStartSel[0] == TEXT('\r'))
                {
                    if(lpszStartSel[1] != TEXT('\0') && lpszStartSel[1] == TEXT('\n'))
                    {
                        ChatData.uval.cd_char.SelPos=MAKELONG(LOWORD(ChatData.uval.cd_char.SelPos),
                                                              HIWORD(ChatData.uval.cd_char.SelPos)+2);
                    }
                    else
                    {
                        ChatData.uval.cd_char.SelPos=MAKELONG(LOWORD(ChatData.uval.cd_char.SelPos)+1,
                                                              HIWORD(ChatData.uval.cd_char.SelPos)+1);
                    }
                }
                else
                {
                    ChatData.uval.cd_char.SelPos=MAKELONG(LOWORD(ChatData.uval.cd_char.SelPos)+1,
                                                          HIWORD(ChatData.uval.cd_char.SelPos)+1);
                }


                LocalUnlock( hText );
            }


            if (gfDbcsEnabled) {
                DWORD dwStart, dwEnd;

                TranslateWideCharPosToMultiBytePos( hwndSnd,
                    (DWORD)LOWORD(ChatData.uval.cd_dbcs.SelPos),
                    (DWORD)HIWORD(ChatData.uval.cd_dbcs.SelPos),
                     &dwStart, &dwEnd );
                ChatData.uval.cd_dbcs.SelPos
                    = MAKELONG((WORD)dwStart, (WORD)dwEnd);
            }

            ChatData.uval.cd_char.Char   = VK_BACK;

            wSet = SET_EN_NOTIFY_WPARAM(ID_EDITSND,EN_CHAR,hwnd);
            lSet = SET_EN_NOTIFY_LPARAM(ID_EDITSND,EN_CHAR,hwnd);

            SendMessage(hwndApp,WM_COMMAND,(WPARAM)wSet,(LPARAM)lSet);
        }
        break;
    case WM_CHAR:
        if(wParam != CTRL_V)
        {
            ChatData.type                = CHT_CHAR;
            SendMessage(hwndSnd,EM_GETSEL,(WPARAM)&dwTemp1,(LPARAM)&dwTemp2);
            ChatData.uval.cd_dbcs.SelPos = MAKELONG((WORD)dwTemp1, (WORD)dwTemp2 );

            if (gfDbcsEnabled) {
                DWORD dwStart, dwEnd;

                TranslateWideCharPosToMultiBytePos( hwndSnd,
                    (DWORD)LOWORD(ChatData.uval.cd_dbcs.SelPos),
                    (DWORD)HIWORD(ChatData.uval.cd_dbcs.SelPos),
                     &dwStart, &dwEnd );
                ChatData.uval.cd_dbcs.SelPos
                    = MAKELONG((WORD)dwStart, (WORD)dwEnd);
            }

            ChatData.uval.cd_char.Char   = (WORD)wParam;

            wSet = SET_EN_NOTIFY_WPARAM(ID_EDITSND,EN_CHAR,hwnd);
            lSet = SET_EN_NOTIFY_LPARAM(ID_EDITSND,EN_CHAR,hwnd);

            SendMessage(hwndApp,WM_COMMAND,wSet,lSet);
        }
        break;


    case WM_PASTE:
        ChatData.type                 = (WORD)(ChatState.fUnicode ? CHT_PASTEW : CHT_PASTEA);
        SendMessage(hwndSnd,EM_GETSEL,(WPARAM)&dwTemp1,(LPARAM)&dwTemp2);
        ChatData.uval.cd_paste.SelPos = MAKELONG(dwTemp1,dwTemp2);
        wSet = SET_EN_NOTIFY_WPARAM(ID_EDITSND,EN_PASTE,hwnd);
        lSet = SET_EN_NOTIFY_LPARAM(ID_EDITSND,EN_PASTE,hwnd);

        SendMessage(hwndApp,WM_COMMAND,wSet,lSet);
        break;
    }

    return(CallWindowProc(lpfnOldEditProc,hwnd,msg,wParam,lParam));
}


/*---------------------------------------------------------------------------*\
| APPLICATION CREATE PROCEDURE
|   This is the main event-handler for the WM_CREATE event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMCreateProc(HWND hwnd)
{
    HDC   hdc;
    TCHAR buf[16] = {0};
    RECT  rc;


    // read from ini
    //
    StringCchPrintf(buf, ARRAYSIZE(buf), TEXT("%ld"),GetSysColor(COLOR_WINDOW));
    GetPrivateProfileString(szPref,szBkgnd,buf,szBuf,SZBUFSIZ,szIni);
    SndBrushColor = myatol(szBuf);


    // just in case display driver changed, set the send-color.
    //
    hdc = GetDC (hwnd);
    if(hdc)
    {
        SndBrushColor = GetNearestColor(hdc,SndBrushColor);
        ReleaseDC(hwnd,hdc);
    }

    if(ChatState.fUseOwnFont)
    {
        RcvBrushColor = SndBrushColor;
        RcvColorref   = SndColorref;
    }
    else
        RcvBrushColor = GetSysColor ( COLOR_WINDOW );

    ChatState.fConnected          = FALSE;
    ChatState.fConnectPending     = FALSE;
    ChatState.fIsServer           = FALSE;
    ChatState.fServerVerified     = TRUE;
    ChatState.fInProcessOfDialing = FALSE;
    ChatState.fUnicode            = FALSE;

    CreateTools(hwnd);
    CreateChildWindows(hwnd);

    UpdateButtonStates();

    // determine height of toolbar window and save...
    //
    GetClientRect(hwndToolbar, &rc);
    dyButtonBar = rc.bottom - rc.top;

    // determine height of statusbar window and save...
    GetClientRect(hwndStatus, &rc);
    dyStatus = rc.bottom - rc.top;


    // stuff our local font into one or both edit controls
    //
    hEditSndFont = CreateFontIndirect((LPLOGFONT)&lfSnd);
    if(hEditSndFont)
    {
        SendMessage(hwndSnd,WM_SETFONT,(WPARAM)hEditSndFont,1L);
        if(ChatState.fUseOwnFont)
            SendMessage(hwndRcv,WM_SETFONT,(WPARAM)hEditSndFont,1L);
    }


    hwndActiveEdit = hwndSnd;

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION WININICHANGE PROCEDURE
|   This is the main event-handler for the WM_WININICHANGE event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMWinIniChangeProc(HWND hwnd)
{

    if(hEditSndFont)
    {
        DeleteObject(hEditSndFont);
        hEditSndFont = CreateFontIndirect((LPLOGFONT)&lfSnd);
        if(hEditSndFont)
            SendMessage(hwndSnd,WM_SETFONT,(WPARAM)hEditSndFont,1L);
    }


    if(hEditRcvFont)
    {
        DeleteObject(hEditRcvFont);
        hEditRcvFont = CreateFontIndirect((LPLOGFONT)&lfRcv);
    }


    if(ChatState.fUseOwnFont && hEditSndFont)
        SendMessage(hwndRcv,WM_SETFONT,(WPARAM)hEditSndFont,1L);
    else
    {
        if(hEditRcvFont)
            SendMessage(hwndRcv,WM_SETFONT,(WPARAM)hEditRcvFont,1L);
    }


    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION ERASEBKGND PROCEDURE
|   This is the main event-handler for the WM_ERASEBKBND event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
BOOL appWMEraseBkGndProc(HWND hwnd)
{
    BOOL bErase;


    bErase = IsIconic(hwnd) ? TRUE : FALSE;

    return(bErase);
}


/*---------------------------------------------------------------------------*\
| APPLICATION SETFOCUS PROCEDURE
|   This is the main event-handler for the WM_SETFOCUS event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMSetFocusProc(HWND hwnd)
{
    SetFocus(hwndActiveEdit);

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION CTLCOLOR PROCEDURE
|   This is the main event-handler for the WM_CTLCOLOR event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
HBRUSH appWMCtlColorProc(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    HDC    hDC;
    HWND   hWndCtl;
    HBRUSH hBrush;


    hBrush  = NULL;
    hDC     = GET_WM_CTLCOLOREDIT_HDC(wParam,lParam);
    hWndCtl = GET_WM_CTLCOLOREDIT_HWND(wParam,lParam);


    if(hWndCtl == hwndSnd)
    {
        SetTextColor(hDC,SndColorref);
        SetBkColor(hDC,SndBrushColor);

        hBrush = hEditSndBrush;
    }
    else
    if(hWndCtl == hwndRcv)
    {
        if(ChatState.fUseOwnFont)
        {
            SetTextColor(hDC,SndColorref);
            SetBkColor(hDC,SndBrushColor);
        }
        else
        {
            SetTextColor(hDC,RcvColorref);
            SetBkColor(hDC,RcvBrushColor);
        }

        hBrush = hEditRcvBrush;
    }

    return(hBrush);
}


/*---------------------------------------------------------------------------*\
| APPLICATION SELECTMENU PROCEDURE
|   This is the main event-handler for the WM_MENUSELECT event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMMenuSelectProc(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    if(wParam == IDM_TOPMOST)
    {
        if(LoadString(hInst,MH_BASE+IDM_TOPMOST,szBuf,SZBUFSIZ))
            SendMessage(hwndStatus,SB_SETTEXT,SBT_NOBORDERS|255,(LPARAM)(LPSTR)szBuf);
    }

    MenuHelp((WORD)WM_MENUSELECT,wParam,lParam,GetMenu(hwnd),hInst,hwndStatus,(LPUINT)nIDs);

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION PAINT PROCEDURE
|   This is the main event-handler for the WM_PAINT event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMPaintProc(HWND hwnd)
{
    HDC         hdc;
        PAINTSTRUCT ps;
    RECT        rc;

    hdc = BeginPaint(hwnd,&ps);
    if(hdc)
    {
        if(IsIconic(hwnd))
        {
            //
            //
            DefWindowProc(hwnd,WM_ICONERASEBKGND,(WPARAM)ps.hdc,0L);
            BitBlt(hMemDC,0,0,cxIcon,cyIcon,hdc,0,0,SRCCOPY);
            DrawIcon(hdc,0,0,hPhones[0]);


            // make 2 more copies.
            //
            BitBlt(hMemDC,cxIcon  ,0,cxIcon,cyIcon,hMemDC,0,0,SRCCOPY);
            BitBlt(hMemDC,2*cxIcon,0,cxIcon,cyIcon,hMemDC,0,0,SRCCOPY);

            // draw phones into them.
            //
            DrawIcon(hMemDC,0       ,0,hPhones[0]);
            DrawIcon(hMemDC,cxIcon  ,0,hPhones[1]);
            DrawIcon(hMemDC,2*cxIcon,0,hPhones[2]);
        }
        else
        {

#if BRD > 2
            rc = SndRc;
            rc.top--;
            rc.left--;
            DrawShadowRect(hdc,&rc);
            rc = RcvRc;
            rc.top--;
            rc.left--;
            DrawShadowRect(hdc,&rc);
#endif
        }

        EndPaint ( hwnd, &ps );
    }

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION TIMER PROCEDURE
|   This is the main event-handler for the WM_TIMER event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMTimerProc(HWND hwnd)
{
    HDC   hdc;
    DWORD dummy;


    // Animate the phone icon.
    //
    if(cAnimate)
    {
        if(--cAnimate == 0)
        {
            KillTimer(hwnd,idTimer);
            FlashWindow(hwnd,FALSE);
                }

        if(IsIconic(hwnd))
        {
            hdc = GetDC(hwndApp);
            if(hdc)
            {
                BitBlt(hdc,0,0,cxIcon,cyIcon,hMemDC,ASeq[cAnimate % 4] * cxIcon,0,SRCCOPY);
                ReleaseDC(hwndApp,hdc);
            }
        }

                return;
        }



    // We must be ringing...
    //
    if(!ChatState.fConnectPending)
    {
        KillTimer(hwnd,idTimer);
                return;
        }


    // has the existence of the server been verified (by completion
    // of the async advstart xact)?
    //
    if(!ChatState.fServerVerified)
    {
                return;
        }


    // don't want to lose this...
    //
    DdeKeepStringHandle(idInst,hszLocalName);

    if(DdeClientTransaction(NULL,0L,ghConv,hszLocalName,cf_chatdata,XTYP_ADVSTART,(DWORD)3000L,(LPDWORD)&dummy) == (HDDEDATA)TRUE)
    {
        ChatState.fConnected      = TRUE;
        ChatState.fConnectPending = FALSE;
        UpdateButtonStates();

        KILLSOUND;

        SendFontToPartner();

        StringCchPrintf(szBuf, SZBUFSIZ, szConnectedTo,(LPSTR)szConvPartner);
        SetStatusWindowText(szBuf);

        StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%s - [%s]"),(LPTSTR)szAppName,(LPTSTR)szConvPartner);
        SetWindowText(hwnd,szBuf);


        // allow text entry...
        //
        SendMessage(hwndSnd,EM_SETREADONLY,(WPARAM)FALSE,0L);

        KillTimer(hwnd,idTimer);

        AnnounceSupport();
    }
    else
    {
        // The other party has not answered yet... ring every 6 seconds.
        // Ring local,
        //
        if(!(nConnectAttempt++ % 6))
            DoRing(szWcRingOut);
    }

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION QUERYDRAGICON PROCEDURE
|   This is the main event-handler for the WM_QUERYDRAGICON event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
HICON appWMQueryDragIconProc(HWND hwnd)
{
    HICON hIcon;


    hIcon = hPhones[0];

    return(hIcon);
}


/*---------------------------------------------------------------------------*\
| APPLICATION SIZE PROCEDURE
|   This is the main event-handler for the WM_SIZE event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMSizeProc(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    if(ChatState.fMinimized && ChatState.fConnectPending && ChatState.fIsServer)
    {
        ChatState.fAllowAnswer = TRUE;
        SetStatusWindowText(szConnecting);


        // stop the ringing immediately.
        //
        KILLSOUND;
        if(ChatState.fMMSound)
            sndPlaySound(NULL,SND_ASYNC);

        // cut the animation short.
        //
        if(cAnimate)
            cAnimate = 1;
    }


    //
    //
    InvalidateRect(hwnd,NULL,TRUE);
    SendMessage(hwndToolbar,WM_SIZE,0,0L);
    SendMessage(hwndStatus ,WM_SIZE,0,0L);
    AdjustEditWindows();

    ChatState.fMinimized = (wParam == SIZE_MINIMIZED) ? TRUE : FALSE;

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION INITMENU PROCEDURE
|   This is the main event-handler for the WM_INITMENU event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMInitMenuProc(HMENU hmenu)
{
    UINT status;
    LONG l;
    TCHAR szTest[] = TEXT(" ");
    DWORD dwTemp1,dwTemp2;

    SendMessage(hwndActiveEdit,EM_GETSEL,(LPARAM)&dwTemp1,(WPARAM)&dwTemp2);
    l = MAKELONG(dwTemp1,dwTemp2);

    if(HIWORD(l) != LOWORD(l))
                status = MF_ENABLED;
        else
                status = MF_GRAYED;

    EnableMenuItem(hmenu,IDM_EDITCUT ,(hwndActiveEdit == hwndSnd && ChatState.fConnected) ? status : MF_GRAYED);
    EnableMenuItem(hmenu,IDM_EDITCOPY,status);

    status = MF_GRAYED;
    if(hwndActiveEdit == hwndSnd && ChatState.fConnected && IsClipboardFormatAvailable(CF_TEXT))
    {
        status = MF_ENABLED;
        }
    EnableMenuItem(hmenu,IDM_EDITPASTE,status);


    // select all enabled if control non-empty.
    //
    status = MF_GRAYED;
    if(SendMessage(hwndActiveEdit,WM_GETTEXT,2,(LPARAM)szTest))
                status = MF_ENABLED;
    EnableMenuItem(hmenu,IDM_EDITSELECT,status);


    // can we dial, answer and hangup.
    //
    EnableMenuItem(hmenu,IDM_DIAL  ,(!ChatState.fConnected     && !ChatState.fConnectPending) ? MF_ENABLED : MF_GRAYED);
    EnableMenuItem(hmenu,IDM_ANSWER,(ChatState.fConnectPending && ChatState.fIsServer)        ? MF_ENABLED : MF_GRAYED);
    EnableMenuItem(hmenu,IDM_HANGUP,(ChatState.fConnected      || ChatState.fConnectPending)  ? MF_ENABLED : MF_GRAYED);


    // Is toolbar, statusbar and sound allowed?
    //
    CheckMenuItem(hmenu,IDM_SOUND    ,(ChatState.fSound)     ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hmenu,IDM_TOOLBAR  ,(ChatState.fToolBar)   ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hmenu,IDM_STATUSBAR,(ChatState.fStatusBar) ? MF_CHECKED : MF_UNCHECKED);

    return;
}


/*---------------------------------------------------------------------------*\
| APPLICATION SYSCOMMAND PROCEDURE
|   This is the main event-handler for the WM_SYSCOMMAND event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
LRESULT appWMSysCommandProc(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult;
    HMENU   hmenu;


    lResult = 0l;
    switch(wParam)
    {
        case IDM_TOPMOST:
            ChatState.fTopMost = ChatState.fTopMost ? FALSE : TRUE;

            hmenu = GetSystemMenu(hwnd,FALSE);
            if(hmenu)
                CheckMenuItem(hmenu,IDM_TOPMOST,(ChatState.fTopMost) ? MF_CHECKED : MF_UNCHECKED);

            SetWindowPos(hwnd,ChatState.fTopMost ? HWND_TOPMOST : HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
            break;
    }

    return(lResult);
}


/*---------------------------------------------------------------------------*\
| APPLICATION COMMAND PROCEDURE
|   This is the main event-handler for the WM_COMMAND event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
BOOL appWMCommandProc(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    HDC      hdc;
    int      tmp;
    UINT     uNotify;
    DWORD    dummy;
    DWORD    dwBufSize;
    HDDEDATA hDdeData;
    BOOL     bHandled,bOK,bOKPressed=FALSE;
    WPARAM   wSelStart;
    LPARAM   lSelEnd;


    bHandled = TRUE;
    switch(LOWORD(wParam))
    {
                case ID_EDITRCV:
            uNotify = GET_EN_SETFOCUS_NOTIFY(wParam,lParam);
            switch(uNotify)
            {
                case EN_SETFOCUS:
                    hwndActiveEdit = hwndRcv;
                    break;


                // If the control is out of space, honk.
                //
                case EN_ERRSPACE:
                    MessageBeep(0);
                    break;
                        }
            break;


                case ID_EDITSND:
            uNotify = GET_EN_SETFOCUS_NOTIFY(wParam,lParam);
            switch(uNotify)
            {
                // This string came from the edit-hook
                // procedure.
                //
                case EN_DBCS_STRING:
                    if(ChatState.fConnected)
                    {
                        if(!ChatState.fIsServer)
                        {
                            hDdeData = CreateDbcsStringData();
                            if(hDdeData)
                                DdeClientTransaction((LPBYTE)hDdeData,(DWORD)-1,ghConv,hszTextItem,cf_chatdata,XTYP_POKE,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&dummy);
                        }
                        else
                        {
                            hszConvPartner = DdeCreateStringHandle(idInst,szConvPartner,0);
                            DdePostAdvise(idInst,hszChatTopic,hszConvPartner);
                        }
                    }
                    break;


                // This character came from the edit-hook
                // procedure.
                //
                case EN_CHAR:
                    if(ChatState.fConnected)
                    {
                        if(!ChatState.fIsServer)
                        {
                            hDdeData = CreateCharData();
                            if(hDdeData)
                                DdeClientTransaction((LPBYTE)hDdeData,(DWORD)-1,ghConv,hszTextItem,cf_chatdata,XTYP_POKE,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&dummy);
                        }
                        else
                        {
                            hszConvPartner = DdeCreateStringHandle(idInst,szConvPartner,0);
                            DdePostAdvise(idInst,hszChatTopic,hszConvPartner);
                        }
                    }
                    break;

                case EN_PASTE:
                    if(ChatState.fConnected)
                    {
                        if(!ChatState.fIsServer)
                        {
                            if(IsClipboardFormatAvailable(CF_UNICODETEXT))
                            {
                                hDdeData = CreatePasteData();
                                if(hDdeData)
                                    DdeClientTransaction((LPBYTE)hDdeData,(DWORD)-1,ghConv,hszTextItem,cf_chatdata,XTYP_POKE,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&StrXactID);
                            }
                        }
                        else
                        {
                             hszConvPartner = DdeCreateStringHandle(idInst,szConvPartner,0);
                             DdePostAdvise(idInst,hszChatTopic,hszConvPartner);
                        }
                    }
                    break;

                case EN_SETFOCUS:
                    hwndActiveEdit = hwndSnd;
                    break;

                case EN_ERRSPACE:
                    // If the control is out of space, honk.
                    //
                    MessageBeep(0);
                    break;
                    }
                    break;


        case IDC_TOOLBAR:
            MenuHelp(WM_COMMAND,wParam,lParam,GetMenu(hwnd),hInst,hwndStatus,(LPUINT)nIDs);
            break;


        case IDM_EXIT:
            SendMessage(hwnd,WM_CLOSE,0,0L);
            break;


        case IDM_TOOLBAR:
            if(ChatState.fToolBar)
            {
                ChatState.fToolBar = FALSE;
                ShowWindow(hwndToolbar,SW_HIDE);
                InvalidateRect(hwnd,NULL,TRUE);
                AdjustEditWindows();
            }
            else
            {
                ChatState.fToolBar = TRUE;
                InvalidateRect(hwnd,NULL,TRUE);
                AdjustEditWindows();
                ShowWindow(hwndToolbar,SW_SHOW);
            }
            break;


        case IDM_STATUSBAR:
            if(ChatState.fStatusBar)
            {
                ChatState.fStatusBar = FALSE;
                ShowWindow(hwndStatus,SW_HIDE);
                InvalidateRect(hwnd,NULL,TRUE);
                AdjustEditWindows();
            }
            else
            {
                ChatState.fStatusBar = TRUE;
                InvalidateRect(hwnd,NULL,TRUE);
                AdjustEditWindows();
                ShowWindow(hwndStatus,SW_SHOW);
            }
            break;


        case IDM_SWITCHWIN:
            if(hwndActiveEdit == hwndSnd)
                SetFocus(hwndActiveEdit = hwndRcv);
            else
                SetFocus(hwndActiveEdit = hwndSnd);
            break;


        case IDM_SOUND:
            ChatState.fSound = ChatState.fSound ? FALSE : TRUE;
            break;


        case IDM_COLOR:
            SetFocus(hwndActiveEdit);
            chc.rgbResult = SndBrushColor;

            tmp = ChooseColor((LPCHOOSECOLOR)&chc);
            if(tmp)
            {
                hdc = GetDC(hwnd);
                if(hdc)
                {
                    // must map to solid color (edit-control limitation).
                    //
                    SndBrushColor = GetNearestColor(hdc,chc.rgbResult);
                    ReleaseDC(hwnd,hdc);
                }

                DeleteObject(hEditSndBrush);
                hEditSndBrush = CreateSolidBrush(SndBrushColor);
                InvalidateRect(hwndSnd,NULL,TRUE);

                SaveBkGndToIni();

                if(ChatState.fUseOwnFont)
                {
                    RcvBrushColor = SndBrushColor;
                    DeleteObject(hEditRcvBrush);
                    hEditRcvBrush = CreateSolidBrush(RcvBrushColor);
                    InvalidateRect(hwndRcv, NULL, TRUE);
                }

                if(ChatState.fConnected)
                    SendFontToPartner();
            }
            break;


        case IDM_FONT:
            SetFocus(hwndActiveEdit);
            chf.hwndOwner = hwndSnd;
            chf.rgbColors = SndColorref;

            tmp = ChooseFont((LPCHOOSEFONT)&chf);
            if(tmp)
            {
                if(hEditSndFont)
                    DeleteObject(hEditSndFont);

                hEditSndFont = CreateFontIndirect((LPLOGFONT)&lfSnd);
                if(hEditSndFont)
                {
                    SndColorref = chf.rgbColors;
                    SaveFontToIni();

                    SendMessage(hwndSnd,WM_SETFONT,(WPARAM)hEditSndFont,1L);
                    if(ChatState.fUseOwnFont)
                    {
                        SendMessage(hwndRcv,WM_SETFONT,(WPARAM)hEditSndFont,1L);
                        RcvColorref = SndColorref;
                    }


                    // notify partner of the change
                    //
                    if(ChatState.fConnected)
                        SendFontToPartner();
                }
            }
            break;


        case IDM_DIAL:
            if(ChatState.fConnected)
            {
                SetStatusWindowText(szAlreadyConnect);
                break;
            }

            if(ChatState.fConnectPending)
            {
                SetStatusWindowText ( szAbandonFirst);
                break;
            }

            dwBufSize = SZBUFSIZ;

            WNETGETUSER((LPTSTR)NULL,(LPTSTR)szBuf,&dwBufSize);

            if(GetLastError() == ERROR_NO_NETWORK)
            {
                if(MessageBox(hwnd,szNoNet,TEXT("Chat"),MB_YESNO | MB_ICONQUESTION) == IDNO)
                    break;
            }


            ChatState.fInProcessOfDialing = TRUE;
            if(WNetServerBrowseDialog == NULL || (*WNetServerBrowseDialog)(hwnd,TEXT("MRU_Chat"),szBuf,SZBUFSIZ,0L) == WN_NOT_SUPPORTED)
            {
#if WIN32
                bOKPressed = FALSE;
                *szBuf     = TEXT('\0');


                StringCchCopy(szHelp, SZBUFSIZ, TEXT("winchat.hlp"));
                I_SystemFocusDialog(hwnd,MY_LOGONTYPE,(LPWSTR)szBuf,SZBUFSIZ,&bOKPressed,(LPWSTR)szHelp,IDH_SELECTCOMPUTER);

                if(bOKPressed)
                {
                    bOK    = TRUE;
                    StringCchCopy(szConvPartner, UNCNLEN, szBuf);
                }
#else
                dlgDisplayBox(hInst,hwnd,(LPSTR)MAKEINTRESOURCE(IDD_CONNECT),dlgConnectProc,0l);
#endif
            }

            SetFocus(hwndActiveEdit);

            if(*szBuf && bOKPressed)
            {
                CharUpper(szBuf);

                if((lstrlen(szBuf) > 2)  && (szBuf[0] == TEXT('\\')) && (szBuf[1] == TEXT('\\')))
                    StringCchCopy(szConvPartner, UNCNLEN, szBuf+2);
                else
                    StringCchCopy(szConvPartner, UNCNLEN, szBuf);

                ClearEditControls();

                StringCchPrintf(szBuf, SZBUFSIZ,szDialing,(LPSTR)szConvPartner);
                SetStatusWindowText(szBuf);

#if TESTLOCAL
                StringCchPrintf(szBuf, SZBUFSIZ,TEXT("%s"),(LPTSTR)szServiceName);
                hszConnect = DdeCreateStringHandle(idInst,szBuf,0);
                ghConv     = DdeConnect(idInst,hszConnect,hszChatTopic,NULL);
#else
                StringCchPrintf(szBuf, SZBUFSIZ,TEXT("\\\\%s\\NDDE$"),(LPTSTR)szConvPartner);
                hszConnect = DdeCreateStringHandle(idInst,szBuf,0);
                ghConv     = DdeConnect(idInst,hszConnect,hszChatShare,NULL);
#endif

                if(ghConv == (HCONV)0)
                {
                    SetStatusWindowText(szNoConnect);
                    DdeFreeStringHandle(idInst,hszConnect);
                    ChatState.fInProcessOfDialing = FALSE;
                    break;
                }

                ChatState.fConnectPending = TRUE;
                UpdateButtonStates();

                // set up server verify async xaction.
                //
                ChatState.fServerVerified = FALSE;
                DdeKeepStringHandle(idInst,hszConnectTest);
                DdeClientTransaction(NULL,0L,ghConv,hszConnectTest,cf_chatdata,XTYP_ADVSTART,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&XactID);


                // Indicate that this is a Unicode conversation.
                //
                ChatData.type = CHT_UNICODE;
                hDdeData = CreateCharData ();
                if(hDdeData)
                   DdeClientTransaction((LPBYTE)hDdeData,(DWORD)-1,ghConv,hszTextItem,cf_chatdata,XTYP_POKE,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&dummy);


                // set ring timer...
                // connect attempts every second - will be divided by
                // 6 for actual phone rings. This is done to speed the
                // connection process
                // want first message immediately...
                //
                idTimer = SetTimer(hwnd,1,1000,NULL);
                PostMessage(hwnd,WM_TIMER,1,0L);
                nConnectAttempt = 0;
            }

            ChatState.fInProcessOfDialing = FALSE;
            DdeFreeStringHandle(idInst,hszConnect);
            break;


        case IDM_ANSWER:
            if(ChatState.fConnectPending)
            {
                if(!ChatState.fIsServer)
                {
                    SetStatusWindowText(szYouCaller);
                    break;
                }
                else
                {
                    // allow the connection.
                    //
                    ChatState.fAllowAnswer = TRUE;
                    SetStatusWindowText(szConnecting);


                    // stop the ringing immediately.
                    //
                    if(ChatState.fMMSound)
                        sndPlaySound(NULL,SND_ASYNC);


                    // cut the animation short.
                    //
                    if(cAnimate)
                        cAnimate = 1;
                }
            }
            break;


                case IDM_HANGUP:
            if(!ChatState.fConnected && !ChatState.fConnectPending)
            {
                                break;
                        }


            if(ChatState.fConnectPending && !ChatState.fConnected)
            {
                SetStatusWindowText(szConnectAbandon);
            }
            else
            {
                SetStatusWindowText(szHangingUp);
            }


                        KILLSOUND;

            DdeDisconnect(ghConv);

                        ChatState.fConnectPending = FALSE;
            ChatState.fConnected      = FALSE;
            ChatState.fIsServer       = FALSE;
            ChatState.fUnicode        = FALSE;

#ifdef PROTOCOL_NEGOTIATE
            ChatState.fProtocolSent   = FALSE;
#endif

            // suspend text entry.
            //
            UpdateButtonStates();
            SendMessage(hwndSnd,EM_SETREADONLY,TRUE,0L);
            SetWindowText(hwndApp,szAppName);
            break;


       case IDX_UNICODECONV:
            ChatData.type  = CHT_UNICODE;
            hszConvPartner = DdeCreateStringHandle(idInst,szConvPartner,0);
            DdePostAdvise(idInst,hszChatTopic,hszConvPartner);
            break;


                case IDX_DEFERFONTCHANGE:
                        SendFontToPartner();
            break;

#ifdef PROTOCOL_NEGOTIATE
        case IDX_DEFERPROTOCOL:
            AnnounceSupport();
            break;
#endif

        case IDM_CONTENTS:
            HtmlHelpA(GetDesktopWindow(),"winchat.chm",HH_DISPLAY_TOPIC,0L);
            break;


        case IDM_ABOUT:
            ShellAbout(hwndSnd,szAppName,szNull,hPhones[0]);
                        SetFocus(hwndActiveEdit);
            break;


        case IDM_PREFERENCES:
            DialogBoxParam(hInst,(LPTSTR)MAKEINTRESOURCE(IDD_PREFERENCES),hwnd,dlgPreferencesProc,(LPARAM)0);
            break;


        case IDM_EDITCOPY:
            SendMessage(hwndActiveEdit,WM_COPY,0,0L);
            break;


        case IDM_EDITPASTE:
            SendMessage(hwndActiveEdit,WM_PASTE,0,0L);
            break;


        case IDM_EDITCUT:
            SendMessage(hwndActiveEdit,WM_CUT,0,0L);
            break;


        case IDM_EDITSELECT:
            wSelStart = SET_EM_SETSEL_WPARAM(0,-1);
            lSelEnd   = SET_EM_SETSEL_LPARAM(0,-1);
            SendMessage(hwndActiveEdit,EM_SETSEL,wSelStart,lSelEnd);
            break;


        case IDM_EDITUNDO:
            SendMessage(hwndActiveEdit,EM_UNDO,0,0L);
            break;


        default:
            bHandled = FALSE;
            break;
    }

    return(bHandled);
}


/*---------------------------------------------------------------------------*\
| APPLICATION DESTROY PROCEDURE
|   This is the main event-handler for the WM_DESTROY event.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID appWMDestroyProc(HWND hwnd)
{

    // Abandon transaction if in progress.  Force hangup
    // of conversation.
    //
    if(!ChatState.fServerVerified)
        DdeAbandonTransaction(idInst,ghConv,XactID);
    SendMessage(hwnd,WM_COMMAND,IDM_HANGUP,0L);


    // Destroy resources allocated on behalf of app.
    //
    KILLSOUND;
    DeleteTools(hwnd);


    // Save the state information.
    //
    Wpl.length = sizeof(Wpl);
    if(GetWindowPlacement(hwnd,&Wpl))
        SaveWindowPlacement(&Wpl);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fSound);
    WritePrivateProfileString(szPref, szSnd, szBuf, szIni);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fToolBar);
    WritePrivateProfileString(szPref, szTool, szBuf, szIni);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fStatusBar);
    WritePrivateProfileString(szPref, szStat, szBuf, szIni);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fTopMost);
    WritePrivateProfileString(szPref, szTop, szBuf, szIni);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fSideBySide);
    WritePrivateProfileString(szPref, szSbS, szBuf, szIni);

    StringCchPrintf(szBuf, SZBUFSIZ, TEXT("%d"), (UINT)ChatState.fUseOwnFont);
    WritePrivateProfileString(szPref, szUseOF, szBuf, szIni);

    PostQuitMessage(0);

    return;
}


/*---------------------------------------------------------------------------*\
| ASCII TO LONG
|   This routine converts an ascii string to long.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
LONG FAR myatol(LPTSTR s)
{
        LONG ret = 0L;


    while(*s) ret = ret * 10 + (*s++ - TEXT('0'));

    return(ret);
}

/*---------------------------------------------------------------------------*\
| UPDATE BUTTON STATES
|   This routine updates the menu/toolbar buttons.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID FAR UpdateButtonStates(VOID)
{
    BOOL DialState   = FALSE;
        BOOL AnswerState = FALSE;
        BOOL HangUpState = FALSE;


    if(ChatState.fConnected)
                HangUpState = TRUE;
    else
    if(ChatState.fConnectPending)
    {
        if(!ChatState.fIsServer)
                        HangUpState = TRUE;
                else
                        AnswerState = TRUE;
        }
        else
                DialState = TRUE;

    SendMessage(hwndToolbar,TB_ENABLEBUTTON,IDM_DIAL  ,DialState);
    SendMessage(hwndToolbar,TB_ENABLEBUTTON,IDM_ANSWER,AnswerState);
    SendMessage(hwndToolbar,TB_ENABLEBUTTON,IDM_HANGUP,HangUpState);

    return;
}


/*---------------------------------------------------------------------------*\
| GET COMPUTER NAME
|   This routine returns the computer name of the machine.
|
| created: 31-Dec-92
| history: 31-Dec-92 <chriswil> created.
|
\*---------------------------------------------------------------------------*/
BOOL FAR appGetComputerName(LPTSTR lpszName)
{
    BOOL  bGet;
    DWORD dwSize;


#ifdef WIN32

    dwSize = MAX_COMPUTERNAME_LENGTH+1;
    bGet   = GetComputerName(lpszName,&dwSize);

#else

    bGet   = TRUE;
    dwSize = 0l;
    if(GetPrivateProfileString(szVredir,szComputerName,szNull,lpszName,UNCNLEN,szSysIni))
        OemToAnsi(lpszName,lpszName);

#endif

    return(bGet);
}


/*---------------------------------------------------------------------------*\
| ADJUST EDIT WINDOWS
|   This routine sizes the edit-controls.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID FAR AdjustEditWindows(VOID)
{
    int  tmpsplit;
        RECT rc;


    GetClientRect(hwndApp,&rc);

    rc.top    += ChatState.fToolBar   ? dyButtonBar + BRD : BRD;
    rc.bottom -= ChatState.fStatusBar ? dyStatus    + BRD : BRD;

    if(!ChatState.fSideBySide)
    {
        tmpsplit = rc.top + (rc.bottom - rc.top) / 2;

        SndRc.left   = RcvRc.left  = rc.left  - 1 + BRD;
        SndRc.right  = RcvRc.right = rc.right + 1 - BRD;
        SndRc.top    = rc.top;
                SndRc.bottom = tmpsplit;
        RcvRc.top    = tmpsplit + BRD;
                RcvRc.bottom = rc.bottom;
        }
    else
    {
        tmpsplit = rc.left + (rc.right - rc.left) / 2;

        SndRc.left   = rc.left  - 1   + BRD;
        SndRc.right  = tmpsplit - BRD / 2;
        RcvRc.left   = tmpsplit + BRD / 2;
        RcvRc.right  = rc.right + 1 - BRD;
        SndRc.top    = RcvRc.top    = rc.top;
        SndRc.bottom = RcvRc.bottom = rc.bottom;

    }

    MoveWindow(hwndSnd,SndRc.left,SndRc.top,SndRc.right-SndRc.left,SndRc.bottom-SndRc.top,TRUE);
    MoveWindow(hwndRcv,RcvRc.left,RcvRc.top,RcvRc.right-RcvRc.left,RcvRc.bottom-RcvRc.top,TRUE);

    return;
}


/*---------------------------------------------------------------------------*\
| CLEAR EDIT CONTROLS
|   This routine clears the send/receive edit controls.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID ClearEditControls(VOID)
{
    SendMessage(hwndSnd,EM_SETREADONLY,FALSE,0L);
    SendMessage(hwndSnd,WM_SETTEXT    ,0    ,(LPARAM)(LPSTR)szNull);
    SendMessage(hwndSnd,EM_SETREADONLY,TRUE ,0L);

    SendMessage(hwndRcv,EM_SETREADONLY,FALSE,0L);
    SendMessage(hwndRcv,WM_SETTEXT    ,0    ,(LPARAM)(LPSTR)szNull);
    SendMessage(hwndRcv,EM_SETREADONLY,TRUE ,0L);

    return;
}


/*---------------------------------------------------------------------------*\
| DO RING
|   This routine performs the phone ringing.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID DoRing(LPCTSTR sound)
{
    if(ChatState.fSound)
    {
        if(ChatState.fMMSound)
            sndPlaySound(sound,SND_ASYNC);
        else
            MessageBeep(0);
    }

    return;
}


/*---------------------------------------------------------------------------*\
| DRAW SHADOW RECT
|   This routine draws a shadow outline.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID DrawShadowRect(HDC hdc, LPRECT rc)
{
    HPEN hSavePen = SelectObject(hdc,hShadowPen);


    MoveToEx(hdc,rc->left,rc->bottom,NULL);
    LineTo(hdc,rc->left,rc->top );
    LineTo(hdc,rc->right,rc->top );
    SelectObject(hdc,hHilitePen);
    LineTo(hdc,rc->right,rc->bottom);
    LineTo(hdc,rc->left-1,rc->bottom);
    SelectObject(hdc,hSavePen);

    return;
}

#ifdef PROTOCOL_NEGOTIATE
/*---------------------------------------------------------------------------*\
| ANNOUNCE SUPPORT
|   This routine announces to the partner what we support.
|
| created: 11-Nov-91
| history: 29-Dec-92 <chriswil> ported to NT.
|
\*---------------------------------------------------------------------------*/
VOID AnnounceSupport(VOID)
{
    HDDEDATA hDdeData;
    DWORD    dummy;


    if(ChatState.fConnected)
    {
        ChatData.type = CHT_PROTOCOL;

        if(!ChatState.fIsServer)
        {
            hDdeData = CreateProtocolData();
            if(hDdeData)
                DdeClientTransaction((LPBYTE)hDdeData,(DWORD)-1L,ghConv,hszTextItem,cf_chatdata,XTYP_POKE,(DWORD)TIMEOUT_ASYNC,(LPDWORD)&dummy);
        }
        else
        {
            hszConvPartner = DdeCreateStringHandle(idInst,szConvPartner,0);
            if(hszConvPartner)
                DdePostAdvise(idInst,hszChatTopic,hszConvPartner);
        }

        ChatState.fProtocolSent = TRUE;
    }

    return;
}
#endif


/*---------------------------------------------------------------------------*\
| START INI-FILE MAPPING
|   This routines sets the private-profile settings to go to the registry on\
|   a per-user basis.
|
|
\*---------------------------------------------------------------------------*/
VOID StartIniMapping(VOID)
{
    HKEY  hKey1,hKey2,hKey3,hKeySnd;
    DWORD dwDisp,dwSize;


    if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szIniSection,0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey1,&dwDisp) == ERROR_SUCCESS)
    {
        if(dwDisp == REG_CREATED_NEW_KEY)
        {
            RegSetValueEx(hKey1,TEXT("Preferences"),0,REG_SZ,(LPBYTE)szIniKey1,ByteCountOf(lstrlen(szIniKey1)+1));
            RegSetValueEx(hKey1,TEXT("Font")       ,0,REG_SZ,(LPBYTE)szIniKey2,ByteCountOf(lstrlen(szIniKey2)+1));
        }

        if(RegCreateKeyEx(HKEY_CURRENT_USER,TEXT("Software\\Microsoft\\Winchat"),0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey1,&dwDisp) == ERROR_SUCCESS)
        {
            if(dwDisp == REG_CREATED_NEW_KEY)
            {
                RegCreateKeyEx(HKEY_CURRENT_USER,TEXT("Software\\Microsoft\\Winchat\\Preferences"),0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey2,&dwDisp);
                RegCreateKeyEx(HKEY_CURRENT_USER,TEXT("Software\\Microsoft\\Winchat\\Font")       ,0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey3,&dwDisp);

                RegCloseKey(hKey2);
                RegCloseKey(hKey3);
            }
        }

        RegCloseKey(hKey1);
    }


    // The sndPlaySound() first looks in the registry for the wav-files.  The
    // NT version doesn't have these here at setup, so Winchat will write out
    // the defaults when the strings don't exist.  This will allow uses to change
    // sounds for ringing-in and ringing-out.
    //
    if(RegOpenKeyEx(HKEY_CURRENT_USER,TEXT("Control Panel\\Sounds"),0,KEY_WRITE | KEY_QUERY_VALUE,&hKeySnd) == ERROR_SUCCESS)
    {
        dwSize = 0;
        dwDisp = REG_SZ;
        if(RegQueryValueEx(hKeySnd,TEXT("RingIn"),NULL,&dwDisp,NULL,&dwSize) != ERROR_SUCCESS)
        {
            if(dwSize == 0)
            {
                // Set the wav-file values.  Add (1) extra count to account for the null
                // terminator.
                //
                RegSetValueEx(hKeySnd,TEXT("RingIn") ,0,REG_SZ,(LPBYTE)szIniRingIn ,ByteCountOf(lstrlen(szIniRingIn)+1));
                RegSetValueEx(hKeySnd,TEXT("RingOut"),0,REG_SZ,(LPBYTE)szIniRingOut,ByteCountOf(lstrlen(szIniRingOut)+1));
            }
        }

        RegCloseKey(hKeySnd);
    }

    return;
}



/*---------------------------------------------------------------------------*\
| END INI-FILE MAPPING
|   This routines ends the ini-file mapping.  It doesn't do anything at this
|   point, but I've kept it in for some reason.
|
|
\*---------------------------------------------------------------------------*/
VOID EndIniMapping(VOID)
{
    return;
}