/*---------------------------------------------------------------------------*\ | 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 created. | 29-Dec-92 port to NT, cleanup. | 19-Oct-93 unicode enhancements from a-dianeo. | \*---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include "winchat.h" #include "dialogs.h" #include "globals.h" #include "nddeagnt.h" #include #include #include #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 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 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; } } wcscpy(wszImmFile, 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 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 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 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; } #if 0 // FE: obsolete. leave it here only FYI case WM_IME_REPORT: { LPTSTR lpStrParam,lpStrTmp; HANDLE hTmp; if(wParam == IR_STRING) { if(lpStrParam = GlobalLock((HANDLE)lParam)) { if(hTmp = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,(DWORD)(lstrlen(lpStrParam) + 1))) { ChatData.type = CHT_DBCS_STRING; ChatData.uval.cd_dbcs.SelPos = SendMessage(hwndSnd,EM_GETSEL,0,0L); lpStrTmp = GlobalLock(hTmp); lstrcpy(lpStrTmp, lpStrParam); GlobalUnlock(hTmp); ChatData.uval.cd_dbcs.hString = hTmp; 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(ChatState.fConnected) SendMessage(hwndSnd,EM_REPLACESEL,0,(LPARAM)lpStrParam); GlobalUnlock((HANDLE)lParam); return(TRUE); } else { GlobalUnlock((HANDLE)lParam); break; } } } break; } #endif // FE: obsolete 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 ported to NT. | \*---------------------------------------------------------------------------*/ VOID appWMCreateProc(HWND hwnd) { HDC hdc; TCHAR buf[16] = {0}; RECT rc; // read from ini // wsprintf(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 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 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 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 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 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 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 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(); wsprintf(szBuf,szConnectedTo,(LPSTR)szConvPartner); SetStatusWindowText(szBuf); wsprintf(szBuf,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 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 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 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 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 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'); lstrcpy(szHelp, TEXT("winchat.hlp")); I_SystemFocusDialog(hwnd,MY_LOGONTYPE,(LPWSTR)szBuf,SZBUFSIZ,&bOKPressed,(LPWSTR)szHelp,IDH_SELECTCOMPUTER); if(bOKPressed) { bOK = TRUE; lstrcpy(szConvPartner,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('\\'))) lstrcpy(szConvPartner,szBuf+2); else lstrcpy(szConvPartner,szBuf); ClearEditControls(); wsprintf(szBuf,szDialing,(LPSTR)szConvPartner); SetStatusWindowText(szBuf); #if TESTLOCAL wsprintf(szBuf,TEXT("%s"),(LPTSTR)szServiceName); hszConnect = DdeCreateStringHandle(idInst,szBuf,0); ghConv = DdeConnect(idInst,hszConnect,hszChatTopic,NULL); #else wsprintf(szBuf,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 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); wsprintf(szBuf, TEXT("%d"), (UINT)ChatState.fSound); WritePrivateProfileString(szPref, szSnd, szBuf, szIni); wsprintf(szBuf, TEXT("%d"), (UINT)ChatState.fToolBar); WritePrivateProfileString(szPref, szTool, szBuf, szIni); wsprintf(szBuf, TEXT("%d"), (UINT)ChatState.fStatusBar); WritePrivateProfileString(szPref, szStat, szBuf, szIni); wsprintf(szBuf, TEXT("%d"), (UINT)ChatState.fTopMost); WritePrivateProfileString(szPref, szTop, szBuf, szIni); wsprintf(szBuf, TEXT("%d"), (UINT)ChatState.fSideBySide); WritePrivateProfileString(szPref, szSbS, szBuf, szIni); wsprintf(szBuf, 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 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 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 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 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 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 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 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 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; }