strcpy(r, "putty.cnt");
strcpy(r, PUTTY_HELP_CONTENTS);
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show){    WNDCLASS wndclass;    MSG msg;    int guess_width, guess_height;    hinst = inst;    flags = FLAG_VERBOSE | FLAG_INTERACTIVE;    sk_init();    InitCommonControls();    /* Ensure a Maximize setting in Explorer doesn't maximise the     * config box. */    defuse_showwindow();    if (!init_winver())    {	char *str = dupprintf("%s Fatal Error", appname);	MessageBox(NULL, "Windows refuses to report a version",		   str, MB_OK | MB_ICONEXCLAMATION);	sfree(str);	return 1;    }    /*     * If we're running a version of Windows that doesn't support     * WM_MOUSEWHEEL, find out what message number we should be     * using instead.     */    if (osVersion.dwMajorVersion < 4 ||	(osVersion.dwMajorVersion == 4 && 	 osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT))	wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG");    /*     * See if we can find our Help file.     */    {        char b[2048], *p, *q, *r;        FILE *fp;        GetModuleFileName(NULL, b, sizeof(b) - 1);        r = b;        p = strrchr(b, '\\');        if (p && p >= r) r = p+1;        q = strrchr(b, ':');        if (q && q >= r) r = q+1;        strcpy(r, "putty.hlp");        if ( (fp = fopen(b, "r")) != NULL) {            help_path = dupstr(b);            fclose(fp);        } else            help_path = NULL;        strcpy(r, "putty.cnt");        if ( (fp = fopen(b, "r")) != NULL) {            help_has_contents = TRUE;            fclose(fp);        } else            help_has_contents = FALSE;    }    /*     * Process the command line.     */    {	char *p;	int got_host = 0;	default_protocol = be_default_protocol;	/* Find the appropriate default port. */	{	    int i;	    default_port = 0; /* illegal */	    for (i = 0; backends[i].backend != NULL; i++)		if (backends[i].protocol == default_protocol) {		    default_port = backends[i].backend->default_port;		    break;		}	}	cfg.logtype = LGTYP_NONE;	do_defaults(NULL, &cfg);	p = cmdline;	/*	 * Process a couple of command-line options which are more	 * easily dealt with before the line is broken up into	 * words. These are the soon-to-be-defunct @sessionname and	 * the internal-use-only &sharedmemoryhandle, neither of	 * which are combined with anything else.	 */	while (*p && isspace(*p))	    p++;	if (*p == '@') {	    int i = strlen(p);	    while (i > 1 && isspace(p[i - 1]))		i--;	    p[i] = '\0';	    do_defaults(p + 1, &cfg);	    if (!*cfg.host && !do_config()) {		cleanup_exit(0);	    }	} else if (*p == '&') {	    /*	     * An initial & means we've been given a command line	     * containing the hex value of a HANDLE for a file	     * mapping object, which we must then extract as a	     * config.	     */	    HANDLE filemap;	    Config *cp;	    if (sscanf(p + 1, "%p", &filemap) == 1 &&		(cp = MapViewOfFile(filemap, FILE_MAP_READ,				    0, 0, sizeof(Config))) != NULL) {		cfg = *cp;		UnmapViewOfFile(cp);		CloseHandle(filemap);	    } else if (!do_config()) {		cleanup_exit(0);	    }	} else {	    /*	     * Otherwise, break up the command line and deal with	     * it sensibly.	     */	    int argc, i;	    char **argv;	    	    split_into_argv(cmdline, &argc, &argv, NULL);	    for (i = 0; i < argc; i++) {		char *p = argv[i];		int ret;		ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL,					    1, &cfg);		if (ret == -2) {		    cmdline_error("option \"%s\" requires an argument", p);		} else if (ret == 2) {		    i++;	       /* skip next argument */		} else if (ret == 1) {		    continue;	       /* nothing further needs doing */		} else if (!strcmp(p, "-cleanup")) {		    /*		     * `putty -cleanup'. Remove all registry		     * entries associated with PuTTY, and also find		     * and delete the random seed file.		     */		    char *s1, *s2;		    s1 = dupprintf("This procedure will remove ALL Registry\n"				   "entries associated with %s, and will\n"				   "also remove the random seed file.\n"				   "\n"				   "THIS PROCESS WILL DESTROY YOUR SAVED\n"				   "SESSIONS. Are you really sure you want\n"				   "to continue?", appname);		    s2 = dupprintf("%s Warning", appname);		    if (MessageBox(NULL, s1, s2,				   MB_YESNO | MB_ICONWARNING) == IDYES) {			cleanup_all();		    }		    sfree(s1);		    sfree(s2);		    exit(0);		} else if (*p != '-') {		    char *q = p;		    if (got_host) {			/*			 * If we already have a host name, treat			 * this argument as a port number. NB we			 * have to treat this as a saved -P			 * argument, so that it will be deferred			 * until it's a good moment to run it.			 */			int ret = cmdline_process_param("-P", p, 1, &cfg);			assert(ret == 2);		    } else if (!strncmp(q, "telnet:", 7)) {			/*			 * If the hostname starts with "telnet:",			 * set the protocol to Telnet and process			 * the string as a Telnet URL.			 */			char c;			q += 7;			if (q[0] == '/' && q[1] == '/')			    q += 2;			cfg.protocol = PROT_TELNET;			p = q;			while (*p && *p != ':' && *p != '/')			    p++;			c = *p;			if (*p)			    *p++ = '\0';			if (c == ':')			    cfg.port = atoi(p);			else			    cfg.port = -1;			strncpy(cfg.host, q, sizeof(cfg.host) - 1);			cfg.host[sizeof(cfg.host) - 1] = '\0';			got_host = 1;		    } else {			/*			 * Otherwise, treat this argument as a host			 * name.			 */			while (*p && !isspace(*p))			    p++;			if (*p)			    *p++ = '\0';			strncpy(cfg.host, q, sizeof(cfg.host) - 1);			cfg.host[sizeof(cfg.host) - 1] = '\0';			got_host = 1;		    }		} else {		    cmdline_error("unknown option \"%s\"", p);		}	    }	}	cmdline_run_saved(&cfg);	if (!*cfg.host && !do_config()) {	    cleanup_exit(0);	}	/*	 * Trim leading whitespace off the hostname if it's there.	 */	{	    int space = strspn(cfg.host, " \t");	    memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);	}	/* See if host is of the form user@host */	if (cfg.host[0] != '\0') {	    char *atsign = strrchr(cfg.host, '@');	    /* Make sure we're not overflowing the user field */	    if (atsign) {		if (atsign - cfg.host < sizeof cfg.username) {		    strncpy(cfg.username, cfg.host, atsign - cfg.host);		    cfg.username[atsign - cfg.host] = '\0';		}		memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));	    }	}	/*	 * Trim a colon suffix off the hostname if it's there. In	 * order to protect IPv6 address literals against this	 * treatment, we do not do this if there's _more_ than one	 * colon.	 */	{	    char *c = strchr(cfg.host, ':');	    if (c) {		char *d = strchr(c+1, ':');		if (!d)		    *c = '\0';	    }	}	/*	 * Remove any remaining whitespace from the hostname.	 */	{	    int p1 = 0, p2 = 0;	    while (cfg.host[p2] != '\0') {		if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') {		    cfg.host[p1] = cfg.host[p2];		    p1++;		}		p2++;	    }	    cfg.host[p1] = '\0';	}    }    /* Check for invalid Port number (i.e. zero) */    if (cfg.port == 0) {	char *str = dupprintf("%s Internal Error", appname);	MessageBox(NULL, "Invalid Port Number",		   str, MB_OK | MB_ICONEXCLAMATION);	sfree(str);	cleanup_exit(1);    }    if (!prev) {	wndclass.style = 0;	wndclass.lpfnWndProc = WndProc;	wndclass.cbClsExtra = 0;	wndclass.cbWndExtra = 0;	wndclass.hInstance = inst;	wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));	wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM);	wndclass.hbrBackground = NULL;	wndclass.lpszMenuName = NULL;	wndclass.lpszClassName = appname;	RegisterClass(&wndclass);    }    hwnd = NULL;    memset(&ucsdata, 0, sizeof(ucsdata));    cfgtopalette();    /*     * Guess some defaults for the window size. This all gets     * updated later, so we don't really care too much. However, we     * do want the font width/height guesses to correspond to a     * large font rather than a small one...     */    font_width = 10;    font_height = 20;    extra_width = 25;    extra_height = 28;    guess_width = extra_width + font_width * cfg.width;    guess_height = extra_height + font_height * cfg.height;    {	RECT r;		get_fullscreen_rect(&r);	if (guess_width > r.right - r.left)	    guess_width = r.right - r.left;	if (guess_height > r.bottom - r.top)	    guess_height = r.bottom - r.top;    }    {	int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL;	int exwinmode = 0;	if (!cfg.scrollbar)	    winmode &= ~(WS_VSCROLL);	if (cfg.resize_action == RESIZE_DISABLED)	    winmode &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);	if (cfg.alwaysontop)	    exwinmode |= WS_EX_TOPMOST;	if (cfg.sunken_edge)	    exwinmode |= WS_EX_CLIENTEDGE;	hwnd = CreateWindowEx(exwinmode, appname, appname,			      winmode, CW_USEDEFAULT, CW_USEDEFAULT,			      guess_width, guess_height,			      NULL, NULL, inst, NULL);    }    /*     * Initialise the terminal. (We have to do this _after_     * creating the window, since the terminal is the first thing     * which will call schedule_timer(), which will in turn call     * timer_change_notify() which will expect hwnd to exist.)     */    term = term_init(&cfg, &ucsdata, NULL);    logctx = log_init(NULL, &cfg);    term_provide_logctx(term, logctx);    term_size(term, cfg.height, cfg.width, cfg.savelines);    /*     * Initialise the fonts, simultaneously correcting the guesses     * for font_{width,height}.     */    init_fonts(0,0);    /*     * Correct the guesses for extra_{width,height}.     */    {	RECT cr, wr;	GetWindowRect(hwnd, &wr);	GetClientRect(hwnd, &cr);	offset_width = offset_height = cfg.window_border;	extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2;	extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2;    }    /*     * Resize the window, now we know what size we _really_ want it     * to be.     */    guess_width = extra_width + font_width * term->cols;    guess_height = extra_height + font_height * term->rows;    SetWindowPos(hwnd, NULL, 0, 0, guess_width, guess_height,		 SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);    /*     * Set up a caret bitmap, with no content.     */    {	char *bits;	int size = (font_width + 15) / 16 * 2 * font_height;	bits = snewn(size, char);	memset(bits, 0, size);	caretbm = CreateBitmap(font_width, font_height, 1, 1, bits);	sfree(bits);    }    CreateCaret(hwnd, caretbm, font_width, font_height);    /*     * Initialise the scroll bar.     */    {	SCROLLINFO si;	si.cbSize = sizeof(si);	si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;	si.nMin = 0;	si.nMax = term->rows - 1;	si.nPage = term->rows;	si.nPos = 0;	SetScrollInfo(hwnd, SB_VERT, &si, FALSE);    }    /*     * Prepare the mouse handler.     */    lastact = MA_NOTHING;    lastbtn = MBT_NOTHING;    dbltime = GetDoubleClickTime();    /*     * Set up the session-control options on the system menu.     */    {	HMENU s, m;	int i, j;	char *str;	popup_menus[SYSMENU].menu = GetSystemMenu(hwnd, FALSE);	popup_menus[CTXMENU].menu = CreatePopupMenu();	AppendMenu(popup_menus[CTXMENU].menu, MF_ENABLED, IDM_PASTE, "&Paste");	s = CreateMenu();	get_sesslist(&sesslist, TRUE);	/* skip sesslist.sessions[0] == Default Settings */	for (i = 1;	     i < ((sesslist.nsessions <= MENU_SAVED_MAX+1) ? sesslist.nsessions							   : MENU_SAVED_MAX+1);	     i++)	    AppendMenu(s, MF_ENABLED, IDM_SAVED_MIN + (i-1)*MENU_SAVED_STEP,		       sesslist.sessions[i]);	for (j = 0; j < lenof(popup_menus); j++) {	    m = popup_menus[j].menu;	    AppendMenu(m, MF_SEPARATOR, 0, 0);	    popup_menus[j].specials_submenu_pos = GetMenuItemCount(m);	    AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");	    AppendMenu(m, MF_SEPARATOR, 0, 0);	    AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");	    AppendMenu(m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session");	    AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) s, "Sa&ved Sessions");	    AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings...");	    AppendMenu(m, MF_SEPARATOR, 0, 0);	    AppendMenu(m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard");	    AppendMenu(m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback");	    AppendMenu(m, MF_ENABLED, IDM_RESET, "Rese&t Terminal");	    AppendMenu(m, MF_SEPARATOR, 0, 0);	    AppendMenu(m, (cfg.resize_action == RESIZE_DISABLED) ?		       MF_GRAYED : MF_ENABLED, IDM_FULLSCREEN, "&Full Screen");	    AppendMenu(m, MF_SEPARATOR, 0, 0);	    if (help_path)		AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help");	    str = dupprintf("&About %s", appname);	    AppendMenu(m, MF_ENABLED, IDM_ABOUT, str);	    sfree(str);	}    }    start_backend();    /*     * Set up the initial input locale.     */    set_input_locale(GetKeyboardLayout(0));    /*     * Open the initial log file if there is one.     */    logfopen(logctx);    /*     * Finally show the window!     */    ShowWindow(hwnd, show);    SetForegroundWindow(hwnd);    /*     * Set the palette up.     */    pal = NULL;    logpal = NULL;    init_palette();    term_set_focus(term, GetForegroundWindow() == hwnd);    UpdateWindow(hwnd);    if (GetMessage(&msg, NULL, 0, 0) == 1) {	while (msg.message != WM_QUIT) {	    if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))		DispatchMessage(&msg);	    /* Send the paste buffer if there's anything to send */	    term_paste(term);	    /* If there's nothing new in the queue then we can do everything	     * we've delayed, reading the socket, writing, and repainting	     * the window.	     */	    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))		continue;	    /* The messages seem unreliable; especially if we're being tricky */	    term_set_focus(term, GetForegroundWindow() == hwnd);	    net_pending_errors();	    /* There's no point rescanning everything in the message queue	     * so we do an apparently unnecessary wait here	     */	    WaitMessage();	    if (GetMessage(&msg, NULL, 0, 0) != 1)		break;	}    }    cleanup_exit(msg.wParam);	       /* this doesn't return... */    return msg.wParam;		       /* ... but optimiser doesn't know */}