Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2328 lines
67 KiB

/*---------------------------------------------------------------------------*\
| 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 <tchar.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;
}
}
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 <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;
}
#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<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
//
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 <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();
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 <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');
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 <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);
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 <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;
}