ldisc_send(buf, len);  if (len > 0)
if (len > 0) {  ldisc_send(buf, len);
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,				WPARAM wParam, LPARAM lParam){    HDC hdc;    static int ignore_size = FALSE;    static int ignore_clip = FALSE;    static int just_reconfigged = FALSE;    static int resizing = FALSE;    static int need_backend_resize = FALSE;    static int defered_resize = FALSE;    switch (message) {      case WM_TIMER:	if (pending_netevent)	    enact_pending_netevent();	if (inbuf_head)	    term_out();	noise_regular();	HideCaret(hwnd);	term_update();	ShowCaret(hwnd);	if (cfg.ping_interval > 0) {	    time_t now;	    time(&now);	    if (now - last_movement > cfg.ping_interval) {		back->special(TS_PING);		last_movement = now;	    }	}	return 0;      case WM_CREATE:	break;      case WM_CLOSE:	show_mouseptr(1);	if (!cfg.warn_on_close || session_closed ||	    MessageBox(hwnd,		       "Are you sure you want to close this session?",		       "PuTTY Exit Confirmation",		       MB_ICONWARNING | MB_OKCANCEL) == IDOK)	    DestroyWindow(hwnd);	return 0;      case WM_DESTROY:	show_mouseptr(1);	PostQuitMessage(0);	return 0;      case WM_SYSCOMMAND:	switch (wParam & ~0xF) {       /* low 4 bits reserved to Windows */	  case IDM_SHOWLOG:	    showeventlog(hwnd);	    break;	  case IDM_NEWSESS:	  case IDM_DUPSESS:	  case IDM_SAVEDSESS:	    {		char b[2048];		char c[30], *cl;		int freecl = FALSE;		STARTUPINFO si;		PROCESS_INFORMATION pi;		HANDLE filemap = NULL;		if (wParam == IDM_DUPSESS) {		    /*		     * Allocate a file-mapping memory chunk for the		     * config structure.		     */		    SECURITY_ATTRIBUTES sa;		    Config *p;		    sa.nLength = sizeof(sa);		    sa.lpSecurityDescriptor = NULL;		    sa.bInheritHandle = TRUE;		    filemap = CreateFileMapping((HANDLE) 0xFFFFFFFF,						&sa,						PAGE_READWRITE,						0, sizeof(Config), NULL);		    if (filemap) {			p = (Config *) MapViewOfFile(filemap,						     FILE_MAP_WRITE,						     0, 0, sizeof(Config));			if (p) {			    *p = cfg;  /* structure copy */			    UnmapViewOfFile(p);			}		    }		    sprintf(c, "putty &%p", filemap);		    cl = c;		} else if (wParam == IDM_SAVEDSESS) {		    char *session =			sessions[(lParam - IDM_SAVED_MIN) / 16];		    cl = smalloc(16 + strlen(session));	/* 8, but play safe */		    if (!cl)			cl = NULL;     /* not a very important failure mode */		    else {			sprintf(cl, "putty @%s", session);			freecl = TRUE;		    }		} else		    cl = NULL;		GetModuleFileName(NULL, b, sizeof(b) - 1);		si.cb = sizeof(si);		si.lpReserved = NULL;		si.lpDesktop = NULL;		si.lpTitle = NULL;		si.dwFlags = 0;		si.cbReserved2 = 0;		si.lpReserved2 = NULL;		CreateProcess(b, cl, NULL, NULL, TRUE,			      NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);		if (filemap)		    CloseHandle(filemap);		if (freecl)		    sfree(cl);	    }	    break;	  case IDM_RECONF:	    {		int prev_alwaysontop = cfg.alwaysontop;		int prev_sunken_edge = cfg.sunken_edge;		char oldlogfile[FILENAME_MAX];		int oldlogtype;		int need_setwpos = FALSE;		int old_fwidth, old_fheight;		strcpy(oldlogfile, cfg.logfilename);		oldlogtype = cfg.logtype;		old_fwidth = font_width;		old_fheight = font_height;		GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle));		if (!do_reconfig(hwnd))		    break;		if (strcmp(oldlogfile, cfg.logfilename) ||		    oldlogtype != cfg.logtype) {		    logfclose();       /* reset logging */		    logfopen();		}		just_reconfigged = TRUE;		deinit_fonts();		bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;		und_mode = UND_FONT;		init_fonts(0);		sfree(logpal);		/*		 * Flush the line discipline's edit buffer in the		 * case where local editing has just been disabled.		 */		ldisc_send(NULL, 0);		if (pal)		    DeleteObject(pal);		logpal = NULL;		pal = NULL;		cfgtopalette();		init_palette();		/* Enable or disable the scroll bar, etc */		{		    LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE);		    LONG nexflag, exflag =			GetWindowLong(hwnd, GWL_EXSTYLE);		    nexflag = exflag;		    if (cfg.alwaysontop != prev_alwaysontop) {			if (cfg.alwaysontop) {			    nexflag |= WS_EX_TOPMOST;			    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,					 SWP_NOMOVE | SWP_NOSIZE);			} else {			    nexflag &= ~(WS_EX_TOPMOST);			    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,					 SWP_NOMOVE | SWP_NOSIZE);			}		    }		    if (cfg.sunken_edge)			nexflag |= WS_EX_CLIENTEDGE;		    else			nexflag &= ~(WS_EX_CLIENTEDGE);		    nflg = flag;		    if (cfg.scrollbar)			nflg |= WS_VSCROLL;		    else			nflg &= ~WS_VSCROLL;		    if (cfg.locksize)			nflg &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);		    else			nflg |= (WS_THICKFRAME | WS_MAXIMIZEBOX);		    if (nflg != flag || nexflag != exflag) {			RECT cr, wr;			if (nflg != flag)			    SetWindowLong(hwnd, GWL_STYLE, nflg);			if (nexflag != exflag)			    SetWindowLong(hwnd, GWL_EXSTYLE, nexflag);			SendMessage(hwnd, WM_IGNORE_SIZE, 0, 0);			SetWindowPos(hwnd, NULL, 0, 0, 0, 0,				     SWP_NOACTIVATE | SWP_NOCOPYBITS |				     SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER				     | SWP_FRAMECHANGED);			GetWindowRect(hwnd, &wr);			GetClientRect(hwnd, &cr);			extra_width =			    wr.right - wr.left - cr.right + cr.left;			extra_height =			    wr.bottom - wr.top - cr.bottom + cr.top;			need_setwpos = TRUE;		    }		}		if (cfg.height != rows ||		    cfg.width != cols ||		    old_fwidth != font_width ||		    old_fheight != font_height ||		    cfg.savelines != savelines ||		    cfg.sunken_edge != prev_sunken_edge)			need_setwpos = TRUE;		if (IsZoomed(hwnd)) {		    int w, h;		    RECT cr;		    if (need_setwpos)			defered_resize = TRUE;		    GetClientRect(hwnd, &cr);		    w = cr.right - cr.left;		    h = cr.bottom - cr.top;		    w = w / font_width;		    if (w < 1)			w = 1;		    h = h / font_height;		    if (h < 1)			h = 1;		    term_size(h, w, cfg.savelines);		    InvalidateRect(hwnd, NULL, TRUE);		    back->size();		} else {		    term_size(cfg.height, cfg.width, cfg.savelines);		    InvalidateRect(hwnd, NULL, TRUE);		    if (need_setwpos) {			SetWindowPos(hwnd, NULL, 0, 0,				     extra_width + font_width * cfg.width,				     extra_height +				     font_height * cfg.height,				     SWP_NOACTIVATE | SWP_NOCOPYBITS |				     SWP_NOMOVE | SWP_NOZORDER);		    }		}		/* Oops */		if (cfg.locksize && IsZoomed(hwnd))		    force_normal(hwnd);		set_title(cfg.wintitle);		if (IsIconic(hwnd)) {		    SetWindowText(hwnd,				  cfg.win_name_always ? window_name :				  icon_name);		}	    }	    break;	  case IDM_COPYALL:	    term_copyall();	    break;	  case IDM_CLRSB:	    term_clrsb();	    break;	  case IDM_RESET:	    term_pwron();	    break;	  case IDM_TEL_AYT:	    back->special(TS_AYT);	    break;	  case IDM_TEL_BRK:	    back->special(TS_BRK);	    break;	  case IDM_TEL_SYNCH:	    back->special(TS_SYNCH);	    break;	  case IDM_TEL_EC:	    back->special(TS_EC);	    break;	  case IDM_TEL_EL:	    back->special(TS_EL);	    break;	  case IDM_TEL_GA:	    back->special(TS_GA);	    break;	  case IDM_TEL_NOP:	    back->special(TS_NOP);	    break;	  case IDM_TEL_ABORT:	    back->special(TS_ABORT);	    break;	  case IDM_TEL_AO:	    back->special(TS_AO);	    break;	  case IDM_TEL_IP:	    back->special(TS_IP);	    break;	  case IDM_TEL_SUSP:	    back->special(TS_SUSP);	    break;	  case IDM_TEL_EOR:	    back->special(TS_EOR);	    break;	  case IDM_TEL_EOF:	    back->special(TS_EOF);	    break;	  case IDM_ABOUT:	    showabout(hwnd);	    break;	  default:	    if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {		SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);	    }	}	break;#define X_POS(l) ((int)(short)LOWORD(l))#define Y_POS(l) ((int)(short)HIWORD(l))#define TO_CHR_X(x) (((x)<0 ? (x)-font_width+1 : (x)) / font_width)#define TO_CHR_Y(y) (((y)<0 ? (y)-font_height+1: (y)) / font_height)#define WHEEL_DELTA 120      case WM_MOUSEWHEEL:	{	    wheel_accumulator += (short) HIWORD(wParam);	    wParam = LOWORD(wParam);	    /* process events when the threshold is reached */	    while (abs(wheel_accumulator) >= WHEEL_DELTA) {		int b;		/* reduce amount for next time */		if (wheel_accumulator > 0) {		    b = MBT_WHEEL_UP;		    wheel_accumulator -= WHEEL_DELTA;		} else if (wheel_accumulator < 0) {		    b = MBT_WHEEL_DOWN;		    wheel_accumulator += WHEEL_DELTA;		} else		    break;		if (send_raw_mouse) {		    /* send a mouse-down followed by a mouse up */		    term_mouse(b,			       MA_CLICK,			       TO_CHR_X(X_POS(lParam)),			       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,			       wParam & MK_CONTROL);		    term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),			       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,			       wParam & MK_CONTROL);		} else {		    /* trigger a scroll */		    term_scroll(0,				b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);		}	    }	    return 0;	}      case WM_LBUTTONDOWN:      case WM_MBUTTONDOWN:      case WM_RBUTTONDOWN:      case WM_LBUTTONUP:      case WM_MBUTTONUP:      case WM_RBUTTONUP:	{	    int button, press;	    switch (message) {	      case WM_LBUTTONDOWN:		button = MBT_LEFT;		press = 1;		break;	      case WM_MBUTTONDOWN:		button = MBT_MIDDLE;		press = 1;		break;	      case WM_RBUTTONDOWN:		button = MBT_RIGHT;		press = 1;		break;	      case WM_LBUTTONUP:		button = MBT_LEFT;		press = 0;		break;	      case WM_MBUTTONUP:		button = MBT_MIDDLE;		press = 0;		break;	      case WM_RBUTTONUP:		button = MBT_RIGHT;		press = 0;		break;	      default:		button = press = 0;    /* shouldn't happen */	    }	    show_mouseptr(1);	    if (press) {		click(button,		      TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)),		      wParam & MK_SHIFT, wParam & MK_CONTROL);		SetCapture(hwnd);	    } else {		term_mouse(button, MA_RELEASE,			   TO_CHR_X(X_POS(lParam)),			   TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,			   wParam & MK_CONTROL);		ReleaseCapture();	    }	}	return 0;      case WM_MOUSEMOVE:	show_mouseptr(1);	/*	 * Add the mouse position and message time to the random	 * number noise.	 */	noise_ultralight(lParam);	if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {	    Mouse_Button b;	    if (wParam & MK_LBUTTON)		b = MBT_LEFT;	    else if (wParam & MK_MBUTTON)		b = MBT_MIDDLE;	    else		b = MBT_RIGHT;	    term_mouse(b, MA_DRAG, TO_CHR_X(X_POS(lParam)),		       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,		       wParam & MK_CONTROL);	}	return 0;      case WM_NCMOUSEMOVE:	show_mouseptr(1);	noise_ultralight(lParam);	return 0;      case WM_IGNORE_CLIP:	ignore_clip = wParam;	       /* don't panic on DESTROYCLIPBOARD */	break;      case WM_DESTROYCLIPBOARD:	if (!ignore_clip)	    term_deselect();	ignore_clip = FALSE;	return 0;      case WM_PAINT:	{	    PAINTSTRUCT p;	    HideCaret(hwnd);	    hdc = BeginPaint(hwnd, &p);	    if (pal) {		SelectPalette(hdc, pal, TRUE);		RealizePalette(hdc);	    }	    term_paint(hdc, p.rcPaint.left, p.rcPaint.top,		       p.rcPaint.right, p.rcPaint.bottom);	    SelectObject(hdc, GetStockObject(SYSTEM_FONT));	    SelectObject(hdc, GetStockObject(WHITE_PEN));	    EndPaint(hwnd, &p);	    ShowCaret(hwnd);	}	return 0;      case WM_NETEVENT:	/* Notice we can get multiple netevents, FD_READ, FD_WRITE etc	 * but the only one that's likely to try to overload us is FD_READ.	 * This means buffering just one is fine.	 */	if (pending_netevent)	    enact_pending_netevent();	pending_netevent = TRUE;	pend_netevent_wParam = wParam;	pend_netevent_lParam = lParam;	time(&last_movement);	return 0;      case WM_SETFOCUS:	has_focus = TRUE;	CreateCaret(hwnd, caretbm, font_width, font_height);	ShowCaret(hwnd);	flash_window(0);	       /* stop */	compose_state = 0;	term_out();	term_update();	break;      case WM_KILLFOCUS:	show_mouseptr(1);	has_focus = FALSE;	DestroyCaret();	term_out();	term_update();	break;      case WM_IGNORE_SIZE:	ignore_size = TRUE;	       /* don't panic on next WM_SIZE msg */	break;      case WM_ENTERSIZEMOVE:	EnableSizeTip(1);	resizing = TRUE;	need_backend_resize = FALSE;	break;      case WM_EXITSIZEMOVE:	EnableSizeTip(0);	resizing = FALSE;	if (need_backend_resize)	    back->size();	break;      case WM_SIZING:	{	    int width, height, w, h, ew, eh;	    LPRECT r = (LPRECT) lParam;	    width = r->right - r->left - extra_width;	    height = r->bottom - r->top - extra_height;	    w = (width + font_width / 2) / font_width;	    if (w < 1)		w = 1;	    h = (height + font_height / 2) / font_height;	    if (h < 1)		h = 1;	    UpdateSizeTip(hwnd, w, h);	    ew = width - w * font_width;	    eh = height - h * font_height;	    if (ew != 0) {		if (wParam == WMSZ_LEFT ||		    wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT)		    r->left += ew;		else		    r->right -= ew;	    }	    if (eh != 0) {		if (wParam == WMSZ_TOP ||		    wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)		    r->top += eh;		else		    r->bottom -= eh;	    }	    if (ew || eh)		return 1;	    else		return 0;	}	/* break;  (never reached) */      case WM_SIZE:	if (wParam == SIZE_MINIMIZED) {	    SetWindowText(hwnd,			  cfg.win_name_always ? window_name : icon_name);	    break;	}	if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)	    SetWindowText(hwnd, window_name);	if (!ignore_size) {	    int width, height, w, h;#if 0				       /* we have fixed this using WM_SIZING now */	    int ew, eh;#endif	    width = LOWORD(lParam);	    height = HIWORD(lParam);	    w = width / font_width;	    if (w < 1)		w = 1;	    h = height / font_height;	    if (h < 1)		h = 1;#if 0				       /* we have fixed this using WM_SIZING now */	    ew = width - w * font_width;	    eh = height - h * font_height;	    if (ew != 0 || eh != 0) {		RECT r;		GetWindowRect(hwnd, &r);		SendMessage(hwnd, WM_IGNORE_SIZE, 0, 0);		SetWindowPos(hwnd, NULL, 0, 0,			     r.right - r.left - ew, r.bottom - r.top - eh,			     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);	    }#endif	    if (w != cols || h != rows || just_reconfigged) {		term_invalidate();		term_size(h, w, cfg.savelines);		/*		 * Don't call back->size in mid-resize. (To prevent		 * massive numbers of resize events getting sent		 * down the connection during an NT opaque drag.)		 */		if (!resizing)		    back->size();		else {		    need_backend_resize = TRUE;		    cfg.height = h;		    cfg.width = w;		}		just_reconfigged = FALSE;	    }	}	if (wParam == SIZE_RESTORED && defered_resize) {	    defered_resize = FALSE;	    SetWindowPos(hwnd, NULL, 0, 0,			 extra_width + font_width * cfg.width,			 extra_height + font_height * cfg.height,			 SWP_NOACTIVATE | SWP_NOCOPYBITS |			 SWP_NOMOVE | SWP_NOZORDER);	}	ignore_size = FALSE;	return 0;      case WM_VSCROLL:	switch (LOWORD(wParam)) {	  case SB_BOTTOM:	    term_scroll(-1, 0);	    break;	  case SB_TOP:	    term_scroll(+1, 0);	    break;	  case SB_LINEDOWN:	    term_scroll(0, +1);	    break;	  case SB_LINEUP:	    term_scroll(0, -1);	    break;	  case SB_PAGEDOWN:	    term_scroll(0, +rows / 2);	    break;	  case SB_PAGEUP:	    term_scroll(0, -rows / 2);	    break;	  case SB_THUMBPOSITION:	  case SB_THUMBTRACK:	    term_scroll(1, HIWORD(wParam));	    break;	}	break;      case WM_PALETTECHANGED:	if ((HWND) wParam != hwnd && pal != NULL) {	    HDC hdc = get_ctx();	    if (hdc) {		if (RealizePalette(hdc) > 0)		    UpdateColors(hdc);		free_ctx(hdc);	    }	}	break;      case WM_QUERYNEWPALETTE:	if (pal != NULL) {	    HDC hdc = get_ctx();	    if (hdc) {		if (RealizePalette(hdc) > 0)		    UpdateColors(hdc);		free_ctx(hdc);		return TRUE;	    }	}	return FALSE;      case WM_KEYDOWN:      case WM_SYSKEYDOWN:      case WM_KEYUP:      case WM_SYSKEYUP:	/*	 * Add the scan code and keypress timing to the random	 * number noise.	 */	noise_ultralight(lParam);	/*	 * We don't do TranslateMessage since it disassociates the	 * resulting CHAR message from the KEYDOWN that sparked it,	 * which we occasionally don't want. Instead, we process	 * KEYDOWN, and call the Win32 translator functions so that	 * we get the translations under _our_ control.	 */	{	    unsigned char buf[20];	    int len;	    if (wParam == VK_PROCESSKEY) {		MSG m;		m.hwnd = hwnd;		m.message = WM_KEYDOWN;		m.wParam = wParam;		m.lParam = lParam & 0xdfff;		TranslateMessage(&m);	    } else {		len = TranslateKey(message, wParam, lParam, buf);		if (len == -1)		    return DefWindowProc(hwnd, message, wParam, lParam);		/*		 * We need not bother about stdin backlogs here,		 * because in GUI PuTTY we can't do anything about		 * it anyway; there's no means of asking Windows to		 * hold off on KEYDOWN messages. We _have_ to		 * buffer everything we're sent.		 */		ldisc_send(buf, len);		if (len > 0)		    show_mouseptr(0);	    }	}	return 0;      case WM_INPUTLANGCHANGE:	{	    /* wParam == Font number */	    /* lParam == Locale */	    char lbuf[20];	    HKL NewInputLocale = (HKL) lParam;	    // lParam == GetKeyboardLayout(0);	    GetLocaleInfo(LOWORD(NewInputLocale),			  LOCALE_IDEFAULTANSICODEPAGE, lbuf, sizeof(lbuf));	    kbd_codepage = atoi(lbuf);	}	break;      case WM_IME_COMPOSITION:	{	    HIMC hIMC;	    int n;	    char *buff;   	    if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || 	        osVersion.dwPlatformId == VER_PLATFORM_WIN32s) break; /* no Unicode */	    if ((lParam & GCS_RESULTSTR) == 0) /* Composition unfinished. */		break; /* fall back to DefWindowProc */	    hIMC = ImmGetContext(hwnd);	    n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);	    if (n > 0) {		buff = (char*) smalloc(n);		ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);		luni_send((unsigned short *)buff, n / 2);		free(buff);	    }	    ImmReleaseContext(hwnd, hIMC);	    return 1;	}      case WM_IME_CHAR:	if (wParam & 0xFF00) {	    unsigned char buf[2];	    buf[1] = wParam;	    buf[0] = wParam >> 8;	    lpage_send(kbd_codepage, buf, 2);	} else {	    char c = (unsigned char) wParam;	    lpage_send(kbd_codepage, &c, 1);	}	return (0);      case WM_CHAR:      case WM_SYSCHAR:	/*	 * Nevertheless, we are prepared to deal with WM_CHAR	 * messages, should they crop up. So if someone wants to	 * post the things to us as part of a macro manoeuvre,	 * we're ready to cope.	 */	{	    char c = (unsigned char)wParam;	    lpage_send(CP_ACP, &c, 1);	}	return 0;      case WM_SETCURSOR:	if (send_raw_mouse) {	    SetCursor(LoadCursor(NULL, IDC_ARROW));	    return TRUE;	}    }    return DefWindowProc(hwnd, message, wParam, lParam);}