|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /****************************** Module Header ******************************* ! 13: * Module Name: WINDIFF.C ! 14: * ! 15: * File and directory comparisions. ! 16: * ! 17: * Functions: ! 18: * ! 19: * windiff_UI() ! 20: * WinMain() ! 21: * windiff_usage() ! 22: * Poll() ! 23: * DoResize() ! 24: * AboutBox() ! 25: * DoPrint() ! 26: * FindNextChange() ! 27: * FindPrevChange() ! 28: * WriteProfileInt() ! 29: * ToOutline() ! 30: * ToMoved() ! 31: * do_editfile() ! 32: * do_editthread() ! 33: * SetStatus() ! 34: * SetNames() ! 35: * IsBusy() ! 36: * BusyError() ! 37: * StateToColour() ! 38: * SetSelection() ! 39: * do_gethdr() ! 40: * do_getprops() ! 41: * do_getdata() ! 42: * SvrClose() ! 43: * TableServer() ! 44: * wd_dirdialog() ! 45: * wd_copy() ! 46: * InitApplication() ! 47: * InitInstance() ! 48: * CreateTools() ! 49: * DeleteTools() ! 50: * MainWndProc() ! 51: * SetBusy() ! 52: * SetNotBusy() ! 53: * SetSelection() ! 54: * SetButtonText() ! 55: * ToExpand() ! 56: * ParseArgs() ! 57: * wd_initial() ! 58: * ! 59: * Comments: ! 60: * ! 61: * Compare two directories (including all files and subdirs). Look for names ! 62: * that are present in both (report all that are not). For files that ! 63: * are present in both, produce a line-by-line comparison of the differences ! 64: * between the two files (if any). ! 65: * ! 66: * Overview of Windiff internals - the whole program. ! 67: * ! 68: * Windiff is built from several modules (a "module" has a .h file ! 69: * which describes its interface and a .c file which implements it). ! 70: * Apart from THIS comment which tries to give an overview of the whole ! 71: * scheme of things, each module is as self-contained as possible. ! 72: * This is enforced by the use of opaque data types. Modules cannot ! 73: * see each others' internal data structures. Modules are abstract ! 74: * data types. The term "Module" (from Modula2) and "Class" (from C++) ! 75: * are used synonymously. ! 76: * ! 77: * Windiff - main program - parse arguments, put up main window, ! 78: * handle input, calling other modules as needed ! 79: * invoke table class to create the main display and ! 80: * service callbacks from the table class. ! 81: * Contains global flags for options (e.g. ignore_blanks) ! 82: * list - (in gutils) a generalised LIST of anything data type ! 83: * has full set of operations for insert, delete, join etc. ! 84: * line - a LINE is a numbered line of text. Information is kept to ! 85: * allow fast comparisons of LINEs. A LINE can hold a ! 86: * link to another LINE. The links are used to connect ! 87: * lines in one file to matching lines in the other file. ! 88: * file - a FILEDATA represents a file as a file name in the form ! 89: * of a DIRITEM and a LIST of LINEs ! 90: * scandir - a DIRITEM represents information about a file. (for ! 91: * instance its name, whether it has a local copy). ! 92: * compitem - a COMPITEM is a pair of files together with information ! 93: * on how they compare in the form of a breakdown of the ! 94: * files into a LIST of matching or non-matching sections. ! 95: * Either file can be absent. This module contains the ! 96: * file "contrast" algorithm used for the actual comparison ! 97: * tree (in gutils) A binary tree. Important because it is what ! 98: * gives the file comparison its speed as it makes it ! 99: * an "N log N" algorithm rather than "N squared" ! 100: * complist - a COMPLIST is the master data structure. It has a DIRLIST ! 101: * of the left hand files, a DIRLIST of the right hand files ! 102: * and a LIST of COMPITEMs. The left and right hand DIRLISTs ! 103: * are working data used to produce the COMPLIST. The LIST ! 104: * is displayed as the outline table. Any given COMPITEM can ! 105: * be displayed as an expanded item. ! 106: * section - a SECTION is a section of a file (first line, last line) ! 107: * and information as to what it matches in the other file. ! 108: * bar.c - the picture down the left of the screen ! 109: * has a WNDPROC. ! 110: * view - Although the COMPLIST is the master state, it doesn't do ! 111: * all the work itself. The data is actually displayed by ! 112: * the table class which is highly generalised. View ! 113: * owns a COMPLIST (and therefore calls upon the functions ! 114: * in complist to fill it and interrogate it) and calls ! 115: * upon (and is called back by) the functions in table to ! 116: * actually display it. Read about table in gutils.h ! 117: * table.c (in gutils) a highly generalised system for displaying ! 118: * data in rows and columns. The interface is in gutils.h. ! 119: * status.c (in gutils) the status line at the top. See gutils.h ! 120: ************************************************************************* ! 121: * ! 122: * Overview of this file: ! 123: * ! 124: * We create a table window (gutils.dll) to show the files and the ! 125: * results of their comparisons. We create a COMPLIST object representing ! 126: * a list of files and their differences, and a VIEW object to map between ! 127: * the rows of the table window and the COMPLIST. ! 128: * ! 129: * This module is responsible for creating and managing the main window, ! 130: * placing the child windows (table, status window etc) within it, and ! 131: * handling all menu items. We maintain global option flags set by ! 132: * menu commands. ! 133: * ! 134: * Creating a COMPLIST creates a list of unmatched files, and of matching ! 135: * files that are compared with each other (these are COMPITEMS). ! 136: * The VIEW provides a mapping between rows on the screen, and items in ! 137: * the COMPLIST. ! 138: * ! 139: * This version tries to maintain a responsive user interface by ! 140: * creating worker threads to do long jobs. This potentially creates ! 141: * conflicts between the threads as they will both want to update common ! 142: * variables (for instance the UI thread may be changing the options to ! 143: * exclude identical files while the worker thread is adding in the ! 144: * results of new comparisons). Critical sections are used to manage ! 145: * the conflicts. ! 146: * ! 147: * The Edit options invoke an editor on a separate thread. This allows ! 148: * us to repaint our window and thereby allow the user to refer back to ! 149: * what he saw before invoking the editor. When he's finished editing, ! 150: * we would of course like to refresh things and if this is still on the ! 151: * separate thread it might clash. We avoid this clash by POSTing ourselves ! 152: * a (WM_COMMAND, IDM_UPDATE) message. ! 153: * ! 154: ****************************************************************************/ ! 155: ! 156: #include <windows.h> ! 157: #include <shellapi.h> ! 158: #include <stdlib.h> ! 159: #include <commdlg.h> ! 160: #include <string.h> ! 161: ! 162: #include "gutils.h" ! 163: #include "table.h" ! 164: #include "list.h" ! 165: #include "scandir.h" /* needed for file.h */ ! 166: #include "file.h" /* needed for compitem.h */ ! 167: #include "compitem.h" /* needed for view.h */ ! 168: #include "complist.h" ! 169: #include "view.h" ! 170: #include "state.h" ! 171: #include "windiff.h" ! 172: #include "wdiffrc.h" ! 173: ! 174: ! 175: /*--constants and data types--------------------------------------------*/ ! 176: ! 177: int Version = 2; ! 178: int SubVersion = 01; ! 179: ! 180: /* When we print the current table, we pass this id as the table id ! 181: * When we are queried for the properties of this table, we know they ! 182: * want the printing properties for the current view. We use this to ! 183: * select different fonts and colours for the printer. ! 184: */ ! 185: #define TABID_PRINTER 1 ! 186: ! 187: ! 188: ! 189: /* ! 190: * structure containing args passed to worker thread in initial ! 191: * case (executing command line instructions). ! 192: */ ! 193: typedef struct { ! 194: ! 195: LPSTR first; ! 196: LPSTR second; ! 197: LPSTR savelist; ! 198: UINT saveopts; ! 199: VIEW view; ! 200: BOOL fDeep; ! 201: } THREADARGS, FAR * PTHREADARGS; ! 202: ! 203: ! 204: /* Structure containing all the arguments we'd like to give to do_editfile ! 205: Need a structure because CreateThread only allows for one argument. ! 206: */ ! 207: typedef struct { ! 208: VIEW view; ! 209: int option; ! 210: int selection; ! 211: } EDITARGS, FAR * PEDITARGS; ! 212: ! 213: /*---- colour scheme------------------------------- */ ! 214: ! 215: /* outline */ ! 216: DWORD rgb_outlinehi = RGB(255, 0, 0); /* hilighted files in outline mode */ ! 217: ! 218: /* expand view */ ! 219: DWORD rgb_leftfore = RGB( 0, 0, 0); /* foregrnd for left lines */ ! 220: DWORD rgb_leftback = RGB(255, 0, 0); /* backgrnd for left lines */ ! 221: DWORD rgb_rightfore = RGB( 0, 0, 0); /* foregrnd for right lines*/ ! 222: DWORD rgb_rightback = RGB(255, 255, 0); /* backgrnd for right lines*/ ! 223: ! 224: /* moved lines */ ! 225: DWORD rgb_mleftfore = RGB( 0, 0, 128); /* foregrnd for moved-left */ ! 226: DWORD rgb_mleftback = RGB(255, 0, 0); /* backgrnd for moved-left */ ! 227: DWORD rgb_mrightfore = RGB( 0, 0, 255); /* foregrnd for moved-right*/ ! 228: DWORD rgb_mrightback = RGB(255, 255, 0); /* backgrnd for moved-right*/ ! 229: ! 230: /* bar window */ ! 231: DWORD rgb_barleft = RGB(255, 0, 0); /* bar sections in left only */ ! 232: DWORD rgb_barright = RGB(255, 255, 0); /* bar sections in right only */ ! 233: DWORD rgb_barcurrent = RGB( 0, 0, 255); /* current pos markers in bar */ ! 234: ! 235: ! 236: /* module static data -------------------------------------------------*/ ! 237: ! 238: ! 239: /* current value of window title */ ! 240: char AppTitle[256]; ! 241: ! 242: ! 243: HWND hwndClient; /* main window */ ! 244: HWND hwndRCD; /* table window */ ! 245: HWND hwndStatus; /* status bar across top */ ! 246: HWND hwndBar; /* graphic of sections as vertical bars */ ! 247: ! 248: HACCEL haccel; ! 249: ! 250: /* The status bar told us it should be this high. Rest of client area ! 251: * goes to the hwndBar and hwndRCD. ! 252: */ ! 253: int status_height; ! 254: ! 255: HINSTANCE hInst; /* handle to current app instance */ ! 256: HMENU hMenu; /* handle to menu for hwndClient */ ! 257: ! 258: int nMinMax = SW_SHOWNORMAL; /* default state of window normal */ ! 259: ! 260: /* The message sent to us as a callback by the table window needs to be ! 261: * registered - table_msgcode is the result of the RegisterMessage call ! 262: */ ! 263: UINT table_msgcode; ! 264: ! 265: /* True if we are currently doing some scan or comparison. ! 266: * Must get critical section before checking/changing this (call ! 267: * SetBusy. ! 268: */ ! 269: BOOL fBusy = FALSE; ! 270: ! 271: int selection = -1; /* selected row in table*/ ! 272: ! 273: /* Options for DisplayMode field indicating what is currently shown. ! 274: * We use this to know whether or not to show the graphic bar window. ! 275: */ ! 276: #define MODE_NULL 0 /* nothing displayed */ ! 277: #define MODE_OUTLINE 1 /* a list of files displayed */ ! 278: #define MODE_EXPAND 2 /* view is expanded view of one file */ ! 279: ! 280: int DisplayMode = MODE_NULL; /* indicates whether we are in expand mode */ ! 281: ! 282: VIEW current_view = NULL; ! 283: ! 284: /* command line parameters */ ! 285: extern int __argc; ! 286: extern char ** __argv; ! 287: ! 288: BOOL bAbort = FALSE; /* set to request abort of current operation */ ! 289: ! 290: char editor_cmdline[256] = "notepad %p"; /* editor cmdline */ ! 291: /* slick version is "s %p -#%l" */ ! 292: ! 293: /* app-wide global data --------------------------------------------- */ ! 294: ! 295: /* Handle returned from gmem_init - we use this for all memory allocations */ ! 296: HANDLE hHeap; ! 297: ! 298: /* Current state of menu options */ ! 299: int line_numbers = IDM_LNRS; ! 300: int expand_mode = IDM_BOTHFILES; ! 301: int outline_include = INCLUDE_LEFTONLY|INCLUDE_RIGHTONLY|INCLUDE_SAME|INCLUDE_DIFFER; ! 302: BOOL ignore_blanks = TRUE; ! 303: BOOL picture_mode = TRUE; ! 304: ! 305: /* function prototypes ---------------------------------------------*/ ! 306: ! 307: BOOL InitApplication(HINSTANCE hInstance); ! 308: BOOL InitInstance(HINSTANCE hInstance, int nCmdShow); ! 309: void CreateTools(void); ! 310: void DeleteTools(void); ! 311: long APIENTRY MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam); ! 312: BOOL SetBusy(void); ! 313: void SetNotBusy(void); ! 314: void SetSelection(long rownr); ! 315: void SetButtonText(LPSTR cmd); ! 316: BOOL ToExpand(HWND hwnd); ! 317: void ParseArgs(int argc, char ** argv); ! 318: ! 319: ! 320: DWORD wd_initial(LPVOID arg); ! 321: ! 322: static HANDLE ghThread = NULL; ! 323: ! 324: static DWORD gdwMainThreadId; /* threadid of main (user interface) thread ! 325: initialised in winmain(), thereafter constant. ! 326: See windiff_UI() ! 327: */ ! 328: ! 329: /*************************************************************************** ! 330: * Function: windiff_UI ! 331: * ! 332: * Purpose: ! 333: * ! 334: * If you are about to put up a dialog box or in fact process input in any way ! 335: * on any thread other than the main thread - or if you MIGHT be on a thread other ! 336: * than the main thread, then you must call this function with TRUE before doing ! 337: * it and with FALSE immediately afterwards. Otherwise you will get one of a ! 338: * number of flavours of not-very-responsiveness ! 339: */ ! 340: void windiff_UI(BOOL bAttach) ! 341: { ! 342: DWORD dwThreadId = GetCurrentThreadId(); ! 343: if (dwThreadId==gdwMainThreadId) return; ! 344: ! 345: if (bAttach) GetDesktopWindow(); ! 346: AttachThreadInput(dwThreadId, gdwMainThreadId, bAttach); ! 347: } /* windiff_UI */ ! 348: ! 349: /*************************************************************************** ! 350: * Function: WinMain ! 351: * ! 352: * Purpose: ! 353: * ! 354: * Main entry point. Register window classes, create windows, ! 355: * parse command line arguments and then perform a message loop ! 356: */ ! 357: int WINAPI ! 358: WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) ! 359: { ! 360: ! 361: MSG msg; ! 362: ! 363: gdwMainThreadId = GetCurrentThreadId(); ! 364: ! 365: /* create any pens/brushes etc and read in profile defaults */ ! 366: CreateTools(); ! 367: ! 368: /* init window class unless other instances running */ ! 369: if (!hPrevInstance) ! 370: if (!InitApplication(hInstance)) ! 371: return(FALSE); ! 372: ! 373: ! 374: /* init this instance - create all the windows */ ! 375: if (!InitInstance(hInstance, nCmdShow)) ! 376: return(FALSE); ! 377: ! 378: ParseArgs(__argc, __argv); ! 379: ! 380: ! 381: /* message loop */ ! 382: while(GetMessage(&msg, NULL, 0, 0)) { ! 383: if (!TranslateAccelerator(hwndClient, haccel, &msg)) { ! 384: TranslateMessage(&msg); ! 385: DispatchMessage(&msg); ! 386: } ! 387: } ! 388: ! 389: return (msg.wParam); ! 390: ! 391: } ! 392: ! 393: /*************************************************************************** ! 394: * Function: InitApplication ! 395: * ! 396: * Purpose: ! 397: * ! 398: * Register window class for the main window and the bar window. ! 399: */ ! 400: BOOL ! 401: InitApplication(HINSTANCE hInstance) ! 402: { ! 403: WNDCLASS wc; ! 404: BOOL resp; ! 405: ! 406: ! 407: /* register the bar window class */ ! 408: InitBarClass(hInstance); ! 409: ! 410: wc.style = 0; ! 411: wc.lpfnWndProc = MainWndProc; ! 412: wc.cbClsExtra = 0; ! 413: wc.cbWndExtra = 0; ! 414: wc.hInstance = hInstance; ! 415: wc.hIcon = LoadIcon(hInstance, "WinDiff"); ! 416: wc.hCursor = LoadCursor(NULL, IDC_ARROW); ! 417: wc.hbrBackground = NULL; ! 418: wc.lpszClassName = "WinDiffViewerClass"; ! 419: wc.lpszMenuName = NULL; ! 420: ! 421: resp = RegisterClass(&wc); ! 422: ! 423: return(resp); ! 424: } ! 425: ! 426: /*************************************************************************** ! 427: * Function: InitInstance ! 428: * ! 429: * Purpose: ! 430: * ! 431: * Create and show the windows ! 432: */ ! 433: BOOL ! 434: InitInstance(HINSTANCE hInstance, int nCmdShow) ! 435: { ! 436: RECT rect; ! 437: HANDLE hstatus; ! 438: int bar_width; ! 439: RECT childrc; ! 440: ! 441: hInst = hInstance; ! 442: ! 443: /* initialise a heap. we use this one heap throughout ! 444: * the app. for all memory requirements ! 445: */ ! 446: hHeap = gmem_init(); ! 447: /* initialise the list package */ ! 448: List_Init(); ! 449: ! 450: ! 451: hMenu = LoadMenu(hInstance, "WinDiffMenu"); ! 452: haccel = LoadAccelerators(hInstance, "WinDiffAccel"); ! 453: ! 454: /* create the main window */ ! 455: hwndClient = CreateWindow("WinDiffViewerClass", ! 456: "WinDiff", ! 457: WS_OVERLAPPEDWINDOW, ! 458: CW_USEDEFAULT, ! 459: CW_USEDEFAULT, ! 460: CW_USEDEFAULT, ! 461: CW_USEDEFAULT, ! 462: NULL, ! 463: hMenu, ! 464: hInstance, ! 465: NULL ! 466: ); ! 467: ! 468: ! 469: ! 470: if (!hwndClient) { ! 471: return(FALSE); ! 472: } ! 473: ! 474: /* create 3 child windows, one status, one table and one bar ! 475: * Initially, the bar window is hidden and covered by the table. ! 476: */ ! 477: ! 478: /* create a status bar window as ! 479: * a child of the main window. ! 480: */ ! 481: ! 482: /* build a status struct for two labels and an abort button */ ! 483: hstatus = StatusAlloc(3); ! 484: StatusAddItem(hstatus, 0, SF_STATIC, SF_LEFT|SF_VAR|SF_SZMIN, IDL_STATLAB, 14, NULL); ! 485: StatusAddItem(hstatus, 1, SF_BUTTON, SF_RIGHT|SF_RAISE, IDM_ABORT, 8, ! 486: "Exit"); ! 487: StatusAddItem(hstatus, 2, SF_STATIC, SF_LOWER|SF_LEFT|SF_VAR, ! 488: IDL_NAMES, 60, NULL); ! 489: ! 490: /* ask the status bar how high it should be for the controls ! 491: * we have chosen, and save this value for re-sizing. ! 492: */ ! 493: status_height = StatusHeight(hstatus); ! 494: ! 495: /* create a window of this height */ ! 496: GetClientRect(hwndClient, &rect); ! 497: childrc = rect; ! 498: childrc.bottom = status_height; ! 499: hwndStatus = StatusCreate(hInst, hwndClient, IDC_STATUS, &childrc, ! 500: hstatus); ! 501: ! 502: /* layout constants are stated as percentages of the window width */ ! 503: bar_width = (rect.right - rect.left) * BAR_WIN_WIDTH / 100; ! 504: ! 505: /* create the table class covering all the remaining part of ! 506: * the main window ! 507: */ ! 508: hwndRCD = CreateWindow(TableClassName, ! 509: NULL, ! 510: WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, ! 511: 0, ! 512: status_height, ! 513: (int)(rect.right - rect.left), ! 514: (int)(rect.bottom - status_height), ! 515: hwndClient, ! 516: (HANDLE) IDC_RCDISP1, ! 517: hInst, ! 518: NULL); ! 519: ! 520: /* create a bar window as a child of the main window. ! 521: * this window remains hidden until we switch into MODE_EXPAND ! 522: */ ! 523: hwndBar = CreateWindow("BarClass", ! 524: NULL, ! 525: WS_CHILD | WS_VISIBLE, ! 526: 0, ! 527: status_height, ! 528: bar_width, ! 529: (int)(rect.bottom - status_height), ! 530: hwndClient, ! 531: (HANDLE) IDC_BAR, ! 532: hInst, ! 533: NULL); ! 534: ! 535: /* nMinMax indicates whether we are to be minimised on startup, ! 536: * on command line parameters ! 537: */ ! 538: ShowWindow(hwndBar, SW_HIDE); ! 539: ! 540: if (GetProfileInt(APPNAME, "OutlineSaved", 0)) ! 541: { ! 542: WINDOWPLACEMENT wp; ! 543: ! 544: /* restore the previous expanded size and position */ ! 545: wp.flags = 0; ! 546: wp.showCmd = GetProfileInt( APPNAME, "OutlineShowCmd", ! 547: SW_SHOWNORMAL); ! 548: wp.ptMaxPosition.x = GetProfileInt( APPNAME, "OutlineMaxX", 0); ! 549: wp.ptMaxPosition.y = GetProfileInt( APPNAME, "OutlineMaxY", 0); ! 550: wp.rcNormalPosition.left = (int)GetProfileInt( APPNAME, "OutlineNormLeft", (UINT)(-1)); ! 551: wp.rcNormalPosition.top = (int)GetProfileInt( APPNAME, "OutlineNormTop", (UINT)(-1)); ! 552: wp.rcNormalPosition.right = (int)GetProfileInt( APPNAME, "OutlineNormRight", (UINT)(-1)); ! 553: wp.rcNormalPosition.bottom = (int)GetProfileInt( APPNAME, "OutlineNormBottom",(UINT)(-1)); ! 554: SetWindowPlacement(hwndClient,&wp); ! 555: } ! 556: else ShowWindow(hwndClient, nMinMax); ! 557: ! 558: UpdateWindow(hwndClient); ! 559: ! 560: ! 561: /* initialise busy flag and status line to show we are idle ! 562: * (ie not comparing or scanning) ! 563: */ ! 564: SetNotBusy(); ! 565: ! 566: return(TRUE); ! 567: ! 568: } /* InitInstance */ ! 569: ! 570: /*************************************************************************** ! 571: * Function: windiff_usage ! 572: * ! 573: * Purpose: ! 574: * ! 575: * Complain to command line users about poor syntax, ! 576: * will be replaced by proper help file. ! 577: */ ! 578: void ! 579: windiff_usage(LPSTR msg) ! 580: { ! 581: int retval; ! 582: if (msg==NULL) ! 583: msg = "windiff {-L} path1 {path2} {-s{slrd} savefile}"; ! 584: ! 585: retval = MessageBox(hwndClient, ! 586: msg, ! 587: "Windiff Usage", MB_ICONINFORMATION|MB_OKCANCEL); ! 588: if (retval == IDCANCEL) { ! 589: exit(1); ! 590: } ! 591: } ! 592: ! 593: /*************************************************************************** ! 594: * Function: ParseArgs ! 595: * ! 596: * Purpose: ! 597: * ! 598: * Parse command line arguments ! 599: * ! 600: * The user can give one or two paths. If only one, we assume the second ! 601: * is '.' for the current directory. If one of the two paths is a directory ! 602: * and the other a file, we compare a file of the same name in the two dirs. ! 603: * ! 604: * The command -s filename causes the outline list to be written to a file ! 605: * and then the program exits. -s{slrd} filename allows selection of which ! 606: * files are written out; by default, we assume -sld for files left and different. ! 607: * ! 608: * -T means tree. Go deep. ! 609: * ! 610: * The default is Deep, -L overrides and implies shallow, -T overrides -L ! 611: */ ! 612: void ! 613: ParseArgs(int argc, char ** argv) ! 614: { ! 615: int i; ! 616: LPSTR chp; ! 617: PTHREADARGS ta; ! 618: DWORD threadid; ! 619: ! 620: /* thread args can't be on the stack since the stack will change ! 621: * before the thread completes execution ! 622: */ ! 623: ta = (PTHREADARGS) gmem_get(hHeap, sizeof(THREADARGS)); ! 624: ta->first = NULL; ! 625: ta->second = NULL; ! 626: ta->savelist = NULL; ! 627: ta->saveopts = 0; ! 628: ta->fDeep = FALSE; /* No -T option seen yet */ ! 629: ! 630: for (i = 1; i < argc; i++) { ! 631: ! 632: /* is this an option ? */ ! 633: if ((argv[i][0] == '-') || (argv[i][0] == '/')) { ! 634: switch(argv[i][1]) { ! 635: ! 636: case 's': ! 637: case 'S': ! 638: /* read letters for the save option: s,l,r,d */ ! 639: for(chp = &argv[i][2]; *chp != '\0'; chp++) { ! 640: switch(*chp) { ! 641: case 's': ! 642: case 'S': ! 643: ta->saveopts |= INCLUDE_SAME; ! 644: break; ! 645: case 'l': ! 646: case 'L': ! 647: ta->saveopts |= INCLUDE_DIFFER; ! 648: break; ! 649: case 'r': ! 650: case 'R': ! 651: ta->saveopts |= INCLUDE_LEFTONLY; ! 652: break; ! 653: case 'd': ! 654: case 'D': ! 655: ta->saveopts |= INCLUDE_RIGHTONLY; ! 656: break; ! 657: default: ! 658: windiff_usage(NULL); ! 659: return; ! 660: } ! 661: } ! 662: ! 663: if (ta->saveopts == 0) { ! 664: /* default to left and differ */ ! 665: ta->saveopts = (INCLUDE_LEFTONLY) | (INCLUDE_DIFFER); ! 666: } ! 667: ta->savelist = argv[++i]; ! 668: break; ! 669: case 't': ! 670: case 'T': ! 671: ta->fDeep = TRUE; ! 672: break; ! 673: default: ! 674: windiff_usage(NULL); ! 675: return; ! 676: } ! 677: } else { ! 678: if (ta->first == NULL) { ! 679: ta->first = argv[i]; ! 680: } else { ! 681: ta->second = argv[i]; ! 682: } ! 683: } ! 684: } ! 685: ! 686: /* set the correct depth */ ! 687: if (ta->fDeep) ! 688: ; /* explicitly set -- leave it alone */ ! 689: else ta->fDeep = TRUE; /* global default */ ! 690: ! 691: /* any paths to scan ? */ ! 692: if (ta->first == NULL) { ! 693: return; ! 694: } ! 695: ! 696: if (ta->second == NULL) { ! 697: ta->second = "."; ! 698: } ! 699: ! 700: SetBusy(); ! 701: ! 702: /* minimise the window if -s flag given */ ! 703: if (ta->savelist != NULL) { ! 704: ShowWindow(hwndClient, SW_MINIMIZE); ! 705: } ! 706: ! 707: /* make an empty view */ ! 708: current_view = view_new(hwndRCD); ! 709: DisplayMode = MODE_OUTLINE; ! 710: ! 711: ta->view = current_view; ! 712: ! 713: /* attempt to create a worker thread */ ! 714: ! 715: ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_initial, (LPVOID) ta, ! 716: 0, &threadid); ! 717: if (ghThread == NULL) ! 718: { ! 719: wd_initial( (LPVOID) ta); ! 720: } ! 721: } /* ParseArgs */ ! 722: ! 723: ! 724: /*************************************************************************** ! 725: * Function: CreateTools ! 726: * ! 727: * Purpose: ! 728: * ! 729: * Create any pens/brushes, and read defaults ! 730: * from the profile file for menu settings etc. ! 731: */ ! 732: void ! 733: CreateTools(void) ! 734: { ! 735: ! 736: /* standard message that table class sends us for ! 737: * notifications and queries. ! 738: */ ! 739: table_msgcode = RegisterWindowMessage(TableMessage); ! 740: ! 741: line_numbers = GetProfileInt(APPNAME, "LineNumbers", line_numbers); ! 742: outline_include = GetProfileInt(APPNAME, "FileInclude", outline_include); ! 743: ignore_blanks = GetProfileInt(APPNAME, "Blanks", ignore_blanks); ! 744: picture_mode = GetProfileInt(APPNAME, "Picture", picture_mode); ! 745: ! 746: GetProfileString(APPNAME, "Editor", editor_cmdline, (LPTSTR)editor_cmdline, ! 747: sizeof(editor_cmdline)); ! 748: InitializeCriticalSection(&CSWindiff); ! 749: ! 750: } ! 751: ! 752: /*************************************************************************** ! 753: * Function: DeleteTools ! 754: * ! 755: * Purpose: ! 756: * ! 757: * Delete any pens or brushes that were created in CreateTools ! 758: */ ! 759: void ! 760: DeleteTools(void) ! 761: { ! 762: ! 763: DeleteCriticalSection(&CSWindiff); ! 764: ! 765: } ! 766: ! 767: ! 768: /*************************************************************************** ! 769: * Function: ! 770: * ! 771: * Purpose: ! 772: * ! 773: * Check whether we have had an abort request (IDM_ABORT), and ! 774: * return TRUE if abort requested, otherwise FALSE ! 775: */ ! 776: BOOL ! 777: Poll(void) ! 778: { ! 779: return(bAbort); ! 780: } ! 781: ! 782: ! 783: /*************************************************************************** ! 784: * Function: DoResize ! 785: * ! 786: * Purpose: ! 787: * ! 788: * Position child windows on a resize of the main window ! 789: */ ! 790: void ! 791: DoResize(HWND hWnd) ! 792: { ! 793: RECT rc; ! 794: int bar_width; ! 795: ! 796: GetClientRect(hWnd, &rc); ! 797: MoveWindow(hwndStatus, 0, 0, rc.right - rc.left, status_height, TRUE); ! 798: ! 799: bar_width = (rc.right - rc.left) * BAR_WIN_WIDTH / 100; ! 800: ! 801: /* bar window is hidden unless in expand mode */ ! 802: if ((DisplayMode == MODE_EXPAND) && (picture_mode)) { ! 803: ShowWindow(hwndBar, SW_SHOW); ! 804: MoveWindow(hwndBar, 0, status_height, ! 805: bar_width, rc.bottom - status_height, TRUE); ! 806: MoveWindow(hwndRCD, bar_width, status_height, ! 807: (rc.right - rc.left) - bar_width, ! 808: rc.bottom - status_height, TRUE); ! 809: } else { ! 810: MoveWindow(hwndRCD, 0, status_height, (rc.right - rc.left), ! 811: rc.bottom - status_height, TRUE); ! 812: ShowWindow(hwndBar, SW_HIDE); ! 813: } ! 814: ! 815: } ! 816: /*************************************************************************** ! 817: * Function: AboutBox ! 818: * ! 819: * Purpose: ! 820: * ! 821: * Standard processing for About box. ! 822: */ ! 823: int APIENTRY ! 824: AboutBox(HWND hDlg, unsigned message, UINT wParam, LONG lParam) ! 825: { ! 826: char ch[256]; ! 827: ! 828: switch (message) { ! 829: ! 830: case WM_INITDIALOG: ! 831: wsprintf((LPTSTR)ch, "%d.%02d", Version, SubVersion); ! 832: SetDlgItemText(hDlg, IDD_VERSION, ch); ! 833: return(TRUE); ! 834: ! 835: case WM_COMMAND: ! 836: switch (GET_WM_COMMAND_ID(wParam, lParam)) { ! 837: case IDOK: ! 838: EndDialog(hDlg, 0); ! 839: return(TRUE); ! 840: } ! 841: break; ! 842: } ! 843: return(FALSE); ! 844: } ! 845: ! 846: ! 847: /* -- menu commands ---------------------------------------------------*/ ! 848: ! 849: /*************************************************************************** ! 850: * Function: DoPrint ! 851: * ! 852: * Purpose: ! 853: * ! 854: * Print the current view ! 855: */ ! 856: void ! 857: DoPrint(void) ! 858: { ! 859: Title head, foot; ! 860: PrintContext context; ! 861: ! 862: /* print context contains the header and footer. Use the ! 863: * default margins and printer selection ! 864: */ ! 865: ! 866: /* we set the table id to be TABID_PRINTER. When the table calls ! 867: * back to get text and properties, we use this to indicate ! 868: * that the table refered to is the 'current_view', but in print ! 869: * mode, and thus we will use different colours/fonts. ! 870: */ ! 871: context.head = &head; ! 872: context.foot = &foot; ! 873: context.margin = NULL; ! 874: context.pd = NULL; ! 875: context.id = TABID_PRINTER; ! 876: ! 877: /* header is filenames or just WinDiff if no names known*/ ! 878: if (strlen(AppTitle) > 0) { ! 879: head.ptext = AppTitle; ! 880: } else { ! 881: head.ptext = "WinDiff"; ! 882: } ! 883: ! 884: /* header is centred, footer is right-aligned and ! 885: * consists of the page number ! 886: */ ! 887: head.props.valid = P_ALIGN; ! 888: head.props.alignment = P_CENTRE; ! 889: foot.ptext = "Page # of $"; ! 890: foot.props.valid = P_ALIGN; ! 891: foot.props.alignment = P_RIGHT; ! 892: ! 893: SendMessage(hwndRCD, TM_PRINT, 0, (DWORD) (LPSTR) &context); ! 894: } ! 895: ! 896: /*************************************************************************** ! 897: * Function: FindNextChange ! 898: * ! 899: * Purpose: ! 900: * ! 901: * Find the next line in the current view that is ! 902: * not STATE_SAME. Start from the current selection, if valid, or ! 903: * from the top of the window if no selection. ! 904: * ! 905: */ ! 906: BOOL ! 907: FindNextChange(void) ! 908: { ! 909: long row; ! 910: ! 911: /* start from the selection or top of the window if no selection */ ! 912: if (selection >= 0) { ! 913: row = selection + 1; ! 914: } else { ! 915: row = (int) SendMessage(hwndRCD, TM_TOPROW, FALSE, 0); ! 916: } ! 917: ! 918: ! 919: /* find the next 'interesting' line */ ! 920: row = view_findchange(current_view, row, TRUE); ! 921: if (row >= 0) { ! 922: SetSelection(row); ! 923: return(TRUE); ! 924: } else { ! 925: windiff_UI(TRUE); ! 926: MessageBox(hwndClient, "No More Changes", "Windiff", ! 927: MB_ICONINFORMATION|MB_OK); ! 928: windiff_UI(FALSE); ! 929: ! 930: return(FALSE); ! 931: } ! 932: } ! 933: ! 934: /*************************************************************************** ! 935: * Function: FindPrevChange ! 936: * ! 937: * Purpose: ! 938: * ! 939: * Find the previous line in the current view that is not STATE_SAME ! 940: */ ! 941: BOOL ! 942: FindPrevChange(void) ! 943: { ! 944: long row; ! 945: ! 946: /* start from the selection or top of window if no selection */ ! 947: if (selection >= 0) { ! 948: row = selection - 1; ! 949: } else { ! 950: row = (int) SendMessage(hwndRCD, TM_TOPROW, FALSE, 0); ! 951: } ! 952: ! 953: /* find the previous 'interesting' line */ ! 954: row = view_findchange(current_view, row, FALSE); ! 955: if (row >= 0) { ! 956: SetSelection(row); ! 957: return(TRUE); ! 958: } else { ! 959: windiff_UI(TRUE); ! 960: MessageBox(hwndClient, "No Previous Changes", "Windiff", ! 961: MB_ICONINFORMATION|MB_OK); ! 962: windiff_UI(FALSE); ! 963: ! 964: return(FALSE); ! 965: } ! 966: ! 967: } ! 968: /*************************************************************************** ! 969: * Function: WriteProfileInt ! 970: * ! 971: */ ! 972: ! 973: BOOL WriteProfileInt(LPSTR AppName, LPSTR Key, int Int) ! 974: { char Str[40]; ! 975: ! 976: wsprintf((LPTSTR)Str, "%d", Int); ! 977: return WriteProfileString(AppName, Key, Str); ! 978: ! 979: } /* WriteProfileInt */ ! 980: ! 981: ! 982: /*************************************************************************** ! 983: * Function: ToExpand ! 984: * ! 985: * Purpose: ! 986: * ! 987: * Switch to expand view of the selected line ! 988: */ ! 989: BOOL ! 990: ToExpand(HWND hwnd) ! 991: { ! 992: if (selection < 0) { ! 993: return(FALSE); ! 994: } ! 995: ! 996: if (!view_isexpanded(current_view)) { ! 997: /* save the current outline size and position */ ! 998: WINDOWPLACEMENT wp; ! 999: if (GetWindowPlacement(hwndClient,&wp)) { ! 1000: WriteProfileInt(APPNAME, "OutlineShowCmd", wp.showCmd); ! 1001: WriteProfileInt(APPNAME, "OutlineMaxX", wp.ptMaxPosition.x); ! 1002: WriteProfileInt(APPNAME, "OutlineMaxY", wp.ptMaxPosition.y); ! 1003: WriteProfileInt(APPNAME, "OutlineNormLeft", wp.rcNormalPosition.left); ! 1004: WriteProfileInt(APPNAME, "OutlineNormTop", wp.rcNormalPosition.top); ! 1005: WriteProfileInt(APPNAME, "OutlineNormRight", wp.rcNormalPosition.right); ! 1006: WriteProfileInt(APPNAME, "OutlineNormBottom", wp.rcNormalPosition.bottom); ! 1007: WriteProfileInt(APPNAME, "OutlineSaved", 1); ! 1008: } ! 1009: ! 1010: /* restore the previous expanded size and position, if any */ ! 1011: if (GetProfileInt(APPNAME, "ExpandedSaved", 0)) { ! 1012: wp.flags = 0; ! 1013: wp.showCmd ! 1014: = GetProfileInt( APPNAME, "ExpandShowCmd" ! 1015: , SW_SHOWMAXIMIZED); ! 1016: wp.ptMaxPosition.x ! 1017: = GetProfileInt( APPNAME, "ExpandMaxX", 0); ! 1018: wp.ptMaxPosition.y ! 1019: = GetProfileInt( APPNAME, "ExpandMaxY", 0); ! 1020: wp.rcNormalPosition.left ! 1021: = GetProfileInt( APPNAME, "ExpandNormLeft" ! 1022: , wp.rcNormalPosition.left); ! 1023: wp.rcNormalPosition.top ! 1024: = GetProfileInt( APPNAME, "ExpandNormTop" ! 1025: , wp.rcNormalPosition.top); ! 1026: wp.rcNormalPosition.right ! 1027: = GetProfileInt( APPNAME, "ExpandNormRight" ! 1028: , wp.rcNormalPosition.right); ! 1029: wp.rcNormalPosition.bottom ! 1030: = GetProfileInt( APPNAME, "ExpandNormBottom" ! 1031: , wp.rcNormalPosition.bottom); ! 1032: SetWindowPlacement(hwndClient,&wp); ! 1033: } ! 1034: else ShowWindow(hwndClient, SW_SHOWMAXIMIZED); ! 1035: } ! 1036: ! 1037: /*change the view mapping to expand mode */ ! 1038: if (view_expand(current_view, selection)) { ! 1039: ! 1040: /* ok - we now have an expanded view - change status ! 1041: * to show this ! 1042: */ ! 1043: ! 1044: DisplayMode = MODE_EXPAND; ! 1045: ! 1046: /* resize to show the graphic bar picture */ ! 1047: DoResize(hwndClient); ! 1048: ! 1049: ! 1050: /* change button,status text-if we are not still busy*/ ! 1051: if (!fBusy) { ! 1052: ! 1053: /* the status field when we are expanded shows the ! 1054: * tag field (normally the file name) for the ! 1055: * item we are expanding ! 1056: */ ! 1057: SetStatus(view_getcurrenttag(current_view) ); ! 1058: SetButtonText("Outline"); ! 1059: } ! 1060: ! 1061: return(TRUE); ! 1062: } ! 1063: return(FALSE); ! 1064: } /* ToExpand */ ! 1065: ! 1066: /*************************************************************************** ! 1067: * Function: ToOutline ! 1068: * ! 1069: * Purpose: ! 1070: * ! 1071: * Switch back to outline view - showing just the list of file names. ! 1072: */ ! 1073: void ! 1074: ToOutline(HWND hwnd) ! 1075: { ! 1076: if (view_isexpanded(current_view)) { ! 1077: /* save the current expanded size and position */ ! 1078: WINDOWPLACEMENT wp; ! 1079: if (GetWindowPlacement(hwndClient,&wp)) { ! 1080: WriteProfileInt(APPNAME, "ExpandShowCmd", wp.showCmd); ! 1081: WriteProfileInt(APPNAME, "ExpandMaxX", wp.ptMaxPosition.x); ! 1082: WriteProfileInt(APPNAME, "ExpandMaxY", wp.ptMaxPosition.y); ! 1083: WriteProfileInt(APPNAME, "ExpandNormLeft", wp.rcNormalPosition.left); ! 1084: WriteProfileInt(APPNAME, "ExpandNormTop", wp.rcNormalPosition.top); ! 1085: WriteProfileInt(APPNAME, "ExpandNormRight", wp.rcNormalPosition.right); ! 1086: WriteProfileInt(APPNAME, "ExpandNormBottom", wp.rcNormalPosition.bottom); ! 1087: WriteProfileInt(APPNAME, "ExpandedSaved", 1); ! 1088: } ! 1089: ! 1090: /* restore the previous expanded size and position, if any */ ! 1091: if (GetProfileInt(APPNAME, "OutlineSaved", 0)) { ! 1092: wp.flags = 0; ! 1093: wp.showCmd ! 1094: = GetProfileInt( APPNAME, "OutlineShowCmd" ! 1095: , SW_SHOWNORMAL); ! 1096: wp.ptMaxPosition.x ! 1097: = GetProfileInt( APPNAME, "OutlineMaxX", 0); ! 1098: wp.ptMaxPosition.y ! 1099: = GetProfileInt( APPNAME, "OutlineMaxY", 0); ! 1100: wp.rcNormalPosition.left ! 1101: = GetProfileInt( APPNAME, "OutlineNormLeft" ! 1102: , wp.rcNormalPosition.left); ! 1103: wp.rcNormalPosition.top ! 1104: = GetProfileInt( APPNAME, "OutlineNormTop" ! 1105: , wp.rcNormalPosition.top); ! 1106: wp.rcNormalPosition.right ! 1107: = GetProfileInt( APPNAME, "OutlineNormRight" ! 1108: , wp.rcNormalPosition.right); ! 1109: wp.rcNormalPosition.bottom ! 1110: = GetProfileInt( APPNAME, "OutlineNormBottom" ! 1111: , wp.rcNormalPosition.bottom); ! 1112: SetWindowPlacement(hwndClient,&wp); ! 1113: } ! 1114: ShowWindow(hwndClient, SW_SHOWNORMAL); ! 1115: } ! 1116: ! 1117: DisplayMode = MODE_OUTLINE; ! 1118: ! 1119: /* switch mapping back to outline view */ ! 1120: view_outline(current_view); ! 1121: ! 1122: /* hide bar window and resize to cover */ ! 1123: DoResize(hwndClient); ! 1124: ! 1125: ! 1126: /* change label on button */ ! 1127: if (!fBusy) { ! 1128: SetButtonText("Expand"); ! 1129: SetStatus(NULL); ! 1130: } ! 1131: } /* ToOutline */ ! 1132: ! 1133: /*************************************************************************** ! 1134: * Function: ToMoved ! 1135: * ! 1136: * Purpose: ! 1137: * ! 1138: * If the user clicks on a MOVED line in expand mode, we jump to the ! 1139: * other line. We return TRUE if this was possible, or FALSE otherwise. ! 1140: */ ! 1141: BOOL ! 1142: ToMoved(HWND hwnd) ! 1143: { ! 1144: BOOL bIsLeft; ! 1145: int linenr, state; ! 1146: long i, total; ! 1147: ! 1148: if (DisplayMode != MODE_EXPAND) { ! 1149: return(FALSE); ! 1150: } ! 1151: if (selection < 0) { ! 1152: return(FALSE); ! 1153: } ! 1154: ! 1155: state = view_getstate(current_view, selection); ! 1156: if (state == STATE_MOVEDLEFT) { ! 1157: bIsLeft = TRUE; ! 1158: /* get the linenr of the other copy */ ! 1159: linenr = abs(view_getlinenr_right(current_view, selection)); ! 1160: } else if (state == STATE_MOVEDRIGHT) { ! 1161: bIsLeft = FALSE; ! 1162: /* get the linenr of the other copy */ ! 1163: linenr = abs(view_getlinenr_left(current_view, selection)); ! 1164: } else { ! 1165: /* not a moved line - so we can't find another copy */ ! 1166: return(FALSE); ! 1167: } ! 1168: ! 1169: /* search the view for this line nr */ ! 1170: total = view_getrowcount(current_view); ! 1171: for (i = 0; i < total; i++) { ! 1172: if (bIsLeft) { ! 1173: if (linenr == view_getlinenr_right(current_view, i)) { ! 1174: /* found it */ ! 1175: SetSelection(i); ! 1176: return(TRUE); ! 1177: } ! 1178: } else { ! 1179: if (linenr == view_getlinenr_left(current_view, i)) { ! 1180: SetSelection(i); ! 1181: return(TRUE); ! 1182: } ! 1183: } ! 1184: } ! 1185: return(FALSE); ! 1186: } ! 1187: ! 1188: /*************************************************************************** ! 1189: * Function: do_editfile ! 1190: * ! 1191: * Purpose: ! 1192: * ! 1193: * Launch an editor on the current file (the file we are expanding, or ! 1194: * in outline mode the selected row. Option allows selection of the ! 1195: * left file, the right file or the composite view of this item. ! 1196: * pe points to a packet of parameters that must be freed before returning. ! 1197: * The return value is meaningless (just to conform to CreateThread). ! 1198: */ ! 1199: LONG ! 1200: do_editfile(PEDITARGS pe) ! 1201: { ! 1202: VIEW view = pe->view; ! 1203: int option = pe->option; ! 1204: int selection = pe->selection; ! 1205: ! 1206: COMPITEM item; ! 1207: LPSTR fname; ! 1208: char cmdline[256]; ! 1209: int currentline; ! 1210: char * pOut = cmdline; ! 1211: char * pIn = editor_cmdline; ! 1212: ! 1213: STARTUPINFO si; ! 1214: PROCESS_INFORMATION pi; ! 1215: ! 1216: item = view_getitem(view, selection); ! 1217: if (item == NULL) { ! 1218: return -1; ! 1219: } ! 1220: ! 1221: fname = compitem_getfilename(item, option); ! 1222: ! 1223: if ( 0 == fname ) ! 1224: { ! 1225: windiff_UI(TRUE); ! 1226: MessageBox(hwndClient, "File does not exist.", ! 1227: "Windiff", MB_ICONSTOP|MB_OK); ! 1228: windiff_UI(FALSE); ! 1229: goto error; ! 1230: } ! 1231: ! 1232: switch ( option ) ! 1233: { ! 1234: case CI_LEFT: ! 1235: currentline = view_getlinenr_left( view, ! 1236: selection > 0 ? selection : 1); ! 1237: break; ! 1238: ! 1239: case CI_RIGHT: ! 1240: currentline = view_getlinenr_right( view, ! 1241: selection > 0 ? selection : 1); ! 1242: break; ! 1243: ! 1244: default: ! 1245: currentline = 1; ! 1246: break; ! 1247: } ! 1248: ! 1249: while( *pIn ) ! 1250: { ! 1251: switch( *pIn ) ! 1252: { ! 1253: case '%': ! 1254: pIn++; ! 1255: switch ( *pIn ) ! 1256: { ! 1257: case 'p': ! 1258: lstrcpy( (LPTSTR)pOut, fname ); ! 1259: while ( *pOut ) ! 1260: pOut++; ! 1261: break; ! 1262: ! 1263: case 'l': ! 1264: _ltoa( currentline, pOut, 10 ); ! 1265: while ( *pOut ) ! 1266: pOut++; ! 1267: break; ! 1268: ! 1269: default: ! 1270: *pOut++ = *pIn; ! 1271: break; ! 1272: } ! 1273: pIn++; ! 1274: break; ! 1275: ! 1276: default: ! 1277: *pOut++ = *pIn++; ! 1278: break; ! 1279: } ! 1280: } ! 1281: ! 1282: ! 1283: /* Launch the process and waits for it to complete */ ! 1284: ! 1285: si.cb = sizeof(STARTUPINFO); ! 1286: si.lpReserved = NULL; ! 1287: si.lpReserved2 = NULL; ! 1288: si.cbReserved2 = 0; ! 1289: si.lpTitle = (LPSTR)cmdline; ! 1290: si.lpDesktop = (LPTSTR)NULL; ! 1291: si.dwFlags = STARTF_FORCEONFEEDBACK; ! 1292: ! 1293: ! 1294: if (!CreateProcess(NULL, ! 1295: cmdline, ! 1296: NULL, ! 1297: NULL, ! 1298: FALSE, ! 1299: NORMAL_PRIORITY_CLASS, ! 1300: NULL, ! 1301: (LPTSTR)NULL, ! 1302: &si, ! 1303: &pi)) { ! 1304: windiff_UI(TRUE); ! 1305: MessageBox(hwndClient, "Failed to launch editor", ! 1306: "Windiff", MB_ICONSTOP|MB_OK); ! 1307: windiff_UI(FALSE); ! 1308: goto error; ! 1309: } ! 1310: ! 1311: /* wait for completion. */ ! 1312: WaitForSingleObject(pi.hProcess, INFINITE); ! 1313: ! 1314: /* close process and thread handles */ ! 1315: CloseHandle(pi.hThread); ! 1316: CloseHandle(pi.hProcess); ! 1317: ! 1318: /* finished with the filename. deletes it if it was a temp. */ ! 1319: compitem_freefilename(item, option, fname); ! 1320: ! 1321: /* ! 1322: * refresh cached view always . A common trick is to edit the ! 1323: * composite file and then save it as a new left or right file. ! 1324: * Equally the user can edit the left and save as a new right. ! 1325: */ ! 1326: ! 1327: /* We want to force both files to be re-read, but it's not a terribly ! 1328: * good idea to throw the lines away on this thread. Someone might ! 1329: * be reading them on another thread! ! 1330: */ ! 1331: /* file_discardlines(compitem_getleftfile(item)) */ ! 1332: /* file_discardlines(compitem_getrightfile(item)) */ ! 1333: ! 1334: /* force the compare to be re-done */ ! 1335: PostMessage(hwndClient, WM_COMMAND, IDM_UPDATE, (LONG)item); ! 1336: error: ! 1337: gmem_free(hHeap, (LPSTR) pe, sizeof(EDITARGS)); ! 1338: ! 1339: return 0; ! 1340: ! 1341: } /* do_editfile */ ! 1342: ! 1343: ! 1344: /*************************************************************************** ! 1345: * Function: do_editthread ! 1346: * ! 1347: * Purpose: ! 1348: * ! 1349: * Launch an editor on a separate thread. It will actually get a separate ! 1350: * process, but we want our own thread in this process. This thread will ! 1351: * wait until it's finished and then order up a refresh of the UI. ! 1352: * Need to give it its parameters as a gmem allocated packet because ! 1353: * it IS on a separate thread. ! 1354: */ ! 1355: void do_editthread(VIEW view, int option) ! 1356: { ! 1357: PEDITARGS pe; ! 1358: HANDLE thread; ! 1359: DWORD threadid; ! 1360: ! 1361: pe = (PEDITARGS) gmem_get(hHeap, sizeof(EDITARGS)); ! 1362: pe->view = view; ! 1363: pe->option = option; ! 1364: pe->selection = selection; ! 1365: ! 1366: thread = CreateThread( NULL ! 1367: , 0 ! 1368: , (LPTHREAD_START_ROUTINE)do_editfile ! 1369: , (LPVOID) pe ! 1370: , 0 ! 1371: , &threadid ! 1372: ); ! 1373: if (thread == NULL) ! 1374: { ! 1375: /* The createthread failed, do without the extra thread - just ! 1376: * call the function synchronously ! 1377: */ ! 1378: do_editfile(pe); ! 1379: } ! 1380: else CloseHandle(thread); ! 1381: } /* do_editthread */ ! 1382: ! 1383: ! 1384: /* status bar and busy flags --------------------------------------------*/ ! 1385: ! 1386: ! 1387: /*************************************************************************** ! 1388: * Function: SetButtonText ! 1389: * ! 1390: * Purpose: ! 1391: * ! 1392: * Set the Text on the statusbar button to reflect the current state ! 1393: */ ! 1394: void ! 1395: SetButtonText(LPSTR cmd) ! 1396: { ! 1397: SendMessage(hwndStatus, SM_SETTEXT, IDM_ABORT, (DWORD) cmd); ! 1398: } ! 1399: ! 1400: /*************************************************************************** ! 1401: * Function: SetStatus ! 1402: * ! 1403: * Purpose: ! 1404: * ! 1405: * Set the status field (left-hand part) of the status bar. ! 1406: */ ! 1407: void ! 1408: SetStatus(LPSTR cmd) ! 1409: { ! 1410: SendMessage(hwndStatus, SM_SETTEXT, IDL_STATLAB, (DWORD) cmd); ! 1411: } ! 1412: ! 1413: ! 1414: /*************************************************************************** ! 1415: * Function: SetNames ! 1416: * ! 1417: * Purpose: ! 1418: * ! 1419: * Set the names field - the central box in the status bar ! 1420: */ ! 1421: void ! 1422: SetNames(LPSTR names) ! 1423: { ! 1424: SendMessage(hwndStatus, SM_SETTEXT, IDL_NAMES, (DWORD) names); ! 1425: if (names == NULL) { ! 1426: AppTitle[0] = '\0'; ! 1427: } else { ! 1428: strncpy(AppTitle, names, sizeof(AppTitle)); ! 1429: } ! 1430: } ! 1431: ! 1432: /*************************************************************************** ! 1433: * Function: SetBusy ! 1434: * ! 1435: * Purpose: ! 1436: * ! 1437: * If we are not already busy, set the busy flag. ! 1438: * ! 1439: * Enter critical section first. ! 1440: */ ! 1441: BOOL ! 1442: SetBusy(void) ! 1443: { ! 1444: HMENU hmenu; ! 1445: ! 1446: ! 1447: WDEnter(); ! 1448: ! 1449: if (fBusy) { ! 1450: WDLeave(); ! 1451: return(FALSE); ! 1452: } ! 1453: ! 1454: ! 1455: fBusy = TRUE; ! 1456: ! 1457: SetStatus("Comparing..."); ! 1458: /* status also on window text, so that you can see even from ! 1459: * the icon when the scan has finished ! 1460: */ ! 1461: SetWindowText(hwndClient, "WinDiff: scanning"); ! 1462: ! 1463: /* disable appropriate parts of menu */ ! 1464: hmenu = GetMenu(hwndClient); ! 1465: EnableMenuItem(hmenu, IDM_FILE,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); ! 1466: EnableMenuItem(hmenu, IDM_DIR,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); ! 1467: EnableMenuItem(hmenu, IDM_PRINT,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); ! 1468: ! 1469: /* enable abort only when busy */ ! 1470: EnableMenuItem(hmenu, IDM_ABORT,MF_ENABLED|MF_BYCOMMAND); ! 1471: SetButtonText("Abort"); /* leave DisplayMode unchanged */ ! 1472: ! 1473: WDLeave(); ! 1474: return(TRUE); ! 1475: } /* SetBusy */ ! 1476: /*************************************************************************** ! 1477: * Function: SetNotBusy ! 1478: * ! 1479: * Purpose: ! 1480: * ! 1481: * This function can be called from the worker thread. ! 1482: * Thus we must not cause any SendMessage calls to windows ! 1483: * owned by the main thread while holding the CritSec or we ! 1484: * could cause deadlock. ! 1485: * ! 1486: * The critsec is only needed to protect the fBusy flag - so ! 1487: * clear the busy flag last, and only get the crit sec as needed. ! 1488: */ ! 1489: void ! 1490: SetNotBusy(void) ! 1491: { ! 1492: HMENU hmenu; ! 1493: ! 1494: /* reset button and status bar (clearing out busy flags) */ ! 1495: if (current_view == NULL) { ! 1496: SetButtonText("Exit"); ! 1497: SetStatus(NULL); ! 1498: DisplayMode = MODE_NULL; ! 1499: } else if (view_isexpanded(current_view)) { ! 1500: SetButtonText("Outline"); ! 1501: SetStatus(view_getcurrenttag(current_view) ); ! 1502: DisplayMode = MODE_EXPAND; ! 1503: } else { ! 1504: SetButtonText("Expand"); ! 1505: SetStatus(NULL); ! 1506: DisplayMode = MODE_OUTLINE; ! 1507: } ! 1508: ! 1509: SetWindowText(hwndClient, "WinDiff"); ! 1510: ! 1511: /* re-enable appropriate parts of menu */ ! 1512: hmenu = GetMenu(hwndClient); ! 1513: EnableMenuItem(hmenu, IDM_FILE,MF_ENABLED|MF_BYCOMMAND); ! 1514: EnableMenuItem(hmenu, IDM_DIR,MF_ENABLED|MF_BYCOMMAND); ! 1515: EnableMenuItem(hmenu, IDM_PRINT,MF_ENABLED|MF_BYCOMMAND); ! 1516: ! 1517: /* disable abort now no longer busy */ ! 1518: EnableMenuItem(hmenu, IDM_ABORT,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); ! 1519: ! 1520: ! 1521: /* clear the busy flag, protected by critical section */ ! 1522: WDEnter(); ! 1523: ! 1524: fBusy = FALSE; ! 1525: bAbort = FALSE; ! 1526: ! 1527: if (ghThread!=NULL){ ! 1528: CloseHandle(ghThread); ! 1529: ghThread = NULL; ! 1530: } ! 1531: WDLeave(); ! 1532: } /* SetNotBusy */ ! 1533: ! 1534: /*************************************************************************** ! 1535: * Function: IsBusy ! 1536: * ! 1537: * Purpose: ! 1538: * ! 1539: * Checks whether or not crit sec is open ! 1540: */ ! 1541: BOOL ! 1542: IsBusy() ! 1543: { ! 1544: BOOL bOK; ! 1545: ! 1546: WDEnter(); ! 1547: bOK = fBusy; ! 1548: WDLeave(); ! 1549: return(bOK); ! 1550: } /* IsBusy */ ! 1551: ! 1552: /*************************************************************************** ! 1553: * Function: BusyError ! 1554: * ! 1555: * Purpose: ! 1556: * ! 1557: * Puts up message box that system is busy. ! 1558: */ ! 1559: void ! 1560: BusyError(void) ! 1561: { ! 1562: windiff_UI(TRUE); ! 1563: MessageBox(hwndClient, ! 1564: "Please wait for current operation to finish", ! 1565: "WinDiff", MB_OK|MB_ICONSTOP); ! 1566: windiff_UI(FALSE); ! 1567: } /* BusyError */ ! 1568: ! 1569: /* --- colour scheme --------------------------------------------------- */ ! 1570: ! 1571: /*************************************************************************** ! 1572: * Function: StateToColour ! 1573: * ! 1574: * Purpose: ! 1575: * ! 1576: * Map the state given into a foreground and a background colour ! 1577: * for states that are highlighted. Return P_FCOLOUR if the foreground ! 1578: * colour (put in *foreground) is to be used, return P_FCOLOUR|P_BCOLOUR if ! 1579: * both *foreground and *background are to be used, or 0 if the default ! 1580: * colours are to be used. ! 1581: */ ! 1582: UINT ! 1583: StateToColour(int state, int col, DWORD FAR * foreground, DWORD FAR * background) ! 1584: { ! 1585: ! 1586: ! 1587: switch (state) { ! 1588: ! 1589: case STATE_DIFFER: ! 1590: /* files that differ are picked out in a foreground highlight, ! 1591: * with the default background ! 1592: */ ! 1593: *foreground = rgb_outlinehi; ! 1594: return(P_FCOLOUR); ! 1595: ! 1596: case STATE_LEFTONLY: ! 1597: /* lines only in the left file */ ! 1598: *foreground = rgb_leftfore; ! 1599: *background = rgb_leftback; ! 1600: return(P_FCOLOUR|P_BCOLOUR); ! 1601: ! 1602: case STATE_RIGHTONLY: ! 1603: /* lines only in the right file */ ! 1604: *foreground = rgb_rightfore; ! 1605: *background = rgb_rightback; ! 1606: return(P_FCOLOUR|P_BCOLOUR); ! 1607: ! 1608: case STATE_MOVEDLEFT: ! 1609: /* displaced lines in both files - left file version */ ! 1610: *foreground = rgb_mleftfore; ! 1611: *background = rgb_mleftback; ! 1612: return(P_FCOLOUR|P_BCOLOUR); ! 1613: ! 1614: case STATE_MOVEDRIGHT: ! 1615: /* displaced lines in both files - right file version */ ! 1616: *foreground = rgb_mrightfore; ! 1617: *background = rgb_mrightback; ! 1618: return(P_FCOLOUR|P_BCOLOUR); ! 1619: ! 1620: default: ! 1621: ! 1622: /* no highlighting - default colours */ ! 1623: return(0); ! 1624: } ! 1625: ! 1626: } ! 1627: ! 1628: /* table window communication routines ---------------------------------*/ ! 1629: ! 1630: /*************************************************************************** ! 1631: * Function: SetSelection ! 1632: * ! 1633: * Purpose: ! 1634: * ! 1635: * Set a given row as the selected row in the table window ! 1636: */ ! 1637: void ! 1638: SetSelection(long rownr) ! 1639: { ! 1640: TableSelection select; ! 1641: ! 1642: select.startrow = rownr; ! 1643: select.startcell = 0; ! 1644: select.nrows = 1; ! 1645: select.ncells = 1; ! 1646: SendMessage(hwndRCD, TM_SELECT, 0, (long) (LPSTR)&select); ! 1647: } ! 1648: ! 1649: ! 1650: /*************************************************************************** ! 1651: * Function: do_gethdr ! 1652: * ! 1653: * Purpose: ! 1654: * ! 1655: * Handle table class call back to get nr of rows and columns, ! 1656: * and properties for the whole table. ! 1657: * The 'table id' is either TABID_PRINTER - meaning we are ! 1658: * printing the current_view, or it is the view to ! 1659: * use for row/column nr information ! 1660: */ ! 1661: long ! 1662: do_gethdr(HWND hwnd, lpTableHdr phdr) ! 1663: { ! 1664: VIEW view; ! 1665: BOOL bIsPrinter = FALSE; ! 1666: ! 1667: if (phdr->id == TABID_PRINTER) { ! 1668: view = current_view; ! 1669: bIsPrinter = TRUE; ! 1670: } else { ! 1671: view = (VIEW) phdr->id; ! 1672: } ! 1673: if (view == NULL) { ! 1674: return(FALSE); ! 1675: } ! 1676: ! 1677: phdr->nrows = view_getrowcount(view); ! 1678: ! 1679: /* three columns: line nr, tag and rest of line */ ! 1680: ! 1681: /* ! 1682: * if IDM_NONRS (no line numbers) is selected, suppress the ! 1683: * line-nr column entirely to save screen space ! 1684: */ ! 1685: if (line_numbers == IDM_NONRS) { ! 1686: phdr->ncols = 2; ! 1687: phdr->fixedcols = 0; ! 1688: } else { ! 1689: phdr->ncols = 3; ! 1690: phdr->fixedcols = 1; ! 1691: } ! 1692: ! 1693: phdr->fixedrows = 0; ! 1694: phdr->fixedselectable = FALSE; ! 1695: phdr->hseparator = TRUE; ! 1696: phdr->vseparator = TRUE; ! 1697: ! 1698: phdr->selectmode = TM_ROW | TM_SINGLE; ! 1699: /* ! 1700: * find if we are in expand mode - ask for the item we are expanding. ! 1701: */ ! 1702: if (view_isexpanded(view) == TRUE) { ! 1703: ! 1704: /* use focus rect as selection mode in expand mode ! 1705: * so as not to interfere with background colours. ! 1706: */ ! 1707: phdr->selectmode |= TM_FOCUS; ! 1708: } else { ! 1709: /* use default solid inversion when possible as it is clearer.*/ ! 1710: phdr->selectmode |= TM_SOLID; ! 1711: } ! 1712: ! 1713: /* please send TQ_SCROLL notifications when the table is scrolled */ ! 1714: phdr->sendscroll = TRUE; ! 1715: phdr->props.valid = 0; ! 1716: ! 1717: return TRUE; ! 1718: } ! 1719: ! 1720: /*************************************************************************** ! 1721: * Function: do_getprops ! 1722: * ! 1723: * Purpose: ! 1724: * ! 1725: * Respond to table callback asking for the size and properties ! 1726: * of each column. Table id is either TABID_PRINTER (meaning the ! 1727: * current_view, for printing) or it is the view to be used. ! 1728: */ ! 1729: long ! 1730: do_getprops(HWND hwnd, lpColPropsList propslist) ! 1731: { ! 1732: int i, cell; ! 1733: BOOL bIsPrinter = FALSE; ! 1734: VIEW view; ! 1735: ! 1736: if (propslist->id == TABID_PRINTER) { ! 1737: view = current_view; ! 1738: bIsPrinter = TRUE; ! 1739: } else { ! 1740: view = (VIEW) propslist->id; ! 1741: } ! 1742: if (view == NULL) { ! 1743: return(FALSE); ! 1744: } ! 1745: ! 1746: /* The table inteface is slightly confused here. we are not ! 1747: * guaranteed which columns we are being asked about, so instead ! 1748: * of just setting each column cols[0], cols[1] etc, we need ! 1749: * to loop through, looking at each column in the table and ! 1750: * seeing which it is. ! 1751: */ ! 1752: for (i = 0; i < propslist->ncols; i++) { ! 1753: cell = i + propslist->startcol; ! 1754: propslist->plist[i].props.valid = 0; ! 1755: ! 1756: /* for all column widths, add on 1 for the NULL char. */ ! 1757: ! 1758: /* ! 1759: * skip the line nr column if IDM_NONRS ! 1760: */ ! 1761: if (line_numbers == IDM_NONRS) { ! 1762: cell++; ! 1763: } ! 1764: ! 1765: if (cell == 0) { ! 1766: /* properties for line nr column */ ! 1767: ! 1768: propslist->plist[i].nchars = view_getwidth(view, 0)+1; ! 1769: propslist->plist[i].props.valid |= P_ALIGN; ! 1770: propslist->plist[i].props.alignment = P_CENTRE; ! 1771: } else if (cell == 1) { ! 1772: ! 1773: /* properties for tag field */ ! 1774: propslist->plist[i].nchars = view_getwidth(view, 1)+1; ! 1775: propslist->plist[i].props.valid |= P_ALIGN; ! 1776: propslist->plist[i].props.alignment = P_LEFT; ! 1777: } else { ! 1778: /* properties for main text column - ! 1779: * use a fixed font unless printing (if ! 1780: * printing, best to use the default font, because ! 1781: * of resolution differences. ! 1782: * add on 8 chars to the width to ensure that ! 1783: * the width of lines beginning with tabs ! 1784: * works out ok ! 1785: */ ! 1786: propslist->plist[i].nchars = view_getwidth(view, 2)+1; ! 1787: propslist->plist[i].props.valid |= P_ALIGN; ! 1788: propslist->plist[i].props.alignment = P_LEFT; ! 1789: if (!bIsPrinter) { ! 1790: propslist->plist[i].props.valid |= P_FONT; ! 1791: propslist->plist[i].props.hFont = ! 1792: GetStockObject(SYSTEM_FIXED_FONT); ! 1793: } ! 1794: } ! 1795: } ! 1796: return (TRUE); ! 1797: } ! 1798: ! 1799: /*************************************************************************** ! 1800: * Function: do_getdata ! 1801: * ! 1802: * Purpose: ! 1803: * ! 1804: * Respond to a table callback asking for the contents of individual cells. ! 1805: * table id is either TABID_PRINTER, or it is a pointer to the view ! 1806: * to use for data. If going to the printer, don't set the ! 1807: * colours (stick to black and white). ! 1808: */ ! 1809: long ! 1810: do_getdata(HWND hwnd, lpCellDataList cdlist) ! 1811: { ! 1812: int start, endcell, col, i; ! 1813: lpCellData cd; ! 1814: VIEW view; ! 1815: LPSTR textp; ! 1816: BOOL bIsPrinter = FALSE; ! 1817: ! 1818: if (cdlist->id == TABID_PRINTER) { ! 1819: view = current_view; ! 1820: bIsPrinter = TRUE; ! 1821: } else { ! 1822: view = (VIEW) cdlist->id; ! 1823: } ! 1824: ! 1825: start = cdlist->startcell; ! 1826: endcell = cdlist->ncells + start; ! 1827: if (cdlist->row >= view_getrowcount(view)) { ! 1828: return(FALSE); ! 1829: } ! 1830: for (i = start; i < endcell; i++) { ! 1831: cd = &cdlist->plist[i - start]; ! 1832: ! 1833: ! 1834: /* skip the line number column if IDM_NONRS */ ! 1835: if (line_numbers == IDM_NONRS) { ! 1836: col = i+1; ! 1837: } else { ! 1838: col = i; ! 1839: } ! 1840: ! 1841: /* set colour of text to mark out ! 1842: * lines that are changed, if not printer - for the ! 1843: * printer everything should stay in the default colours ! 1844: */ ! 1845: ! 1846: if (!bIsPrinter) { ! 1847: ! 1848: /* convert the state of the requested row into a ! 1849: * colour scheme. returns P_FCOLOUR and/or ! 1850: * P_BCOLOUR if it sets either of the colours ! 1851: */ ! 1852: cd->props.valid |= ! 1853: StateToColour(view_getstate(view, cdlist->row), col, ! 1854: &cd->props.forecolour, ! 1855: &cd->props.backcolour); ! 1856: } ! 1857: ! 1858: textp = view_gettext(view, cdlist->row, col); ! 1859: if (cd->nchars != 0) { ! 1860: if (textp == NULL) { ! 1861: cd->ptext[0] = '\0'; ! 1862: } else { ! 1863: strncpy(cd->ptext, textp, cd->nchars -1); ! 1864: cd->ptext[cd->nchars - 1] = '\0'; ! 1865: } ! 1866: } ! 1867: ! 1868: } ! 1869: return(TRUE); ! 1870: } ! 1871: ! 1872: /*************************************************************************** ! 1873: * Function: SvrClose ! 1874: * ! 1875: * Purpose: ! 1876: * ! 1877: * Table window has finished with this view. It can be deleted. ! 1878: */ ! 1879: void ! 1880: SvrClose(void) ! 1881: { ! 1882: view_delete(current_view); ! 1883: current_view = NULL; ! 1884: ! 1885: /* hide picture - only visible when we are in MODE_EXPAND */ ! 1886: DisplayMode = MODE_NULL; ! 1887: DoResize(hwndClient); ! 1888: ! 1889: /* if we already busy when closing this view (ie ! 1890: * we are in the process of starting a new scan, ! 1891: * then leave the status bar alone, otherwise ! 1892: * we should clean up the state of the status bar ! 1893: */ ! 1894: if (!fBusy) { ! 1895: SetButtonText("Exit"); ! 1896: SetNames(NULL); ! 1897: SetStatus(NULL); ! 1898: ! 1899: } ! 1900: ! 1901: } /* SvrClose */ ! 1902: ! 1903: ! 1904: /*************************************************************************** ! 1905: * Function: TableServer ! 1906: * ! 1907: * Purpose: ! 1908: * ! 1909: * Handle callbacks and notifications from the table class ! 1910: */ ! 1911: long ! 1912: TableServer(HWND hwnd, UINT cmd, long lParam) ! 1913: { ! 1914: lpTableHdr phdr; ! 1915: lpColPropsList proplist; ! 1916: lpCellDataList cdlist; ! 1917: lpTableSelection pselect; ! 1918: ! 1919: switch(cmd) { ! 1920: case TQ_GETSIZE: ! 1921: /* get the nr of rows and cols in this table */ ! 1922: phdr = (lpTableHdr) lParam; ! 1923: return(do_gethdr(hwnd, phdr)); ! 1924: ! 1925: case TQ_GETCOLPROPS: ! 1926: /* get the size and properties of each column */ ! 1927: proplist = (lpColPropsList) lParam; ! 1928: return (do_getprops(hwnd, proplist)); ! 1929: ! 1930: case TQ_GETDATA: ! 1931: /* get the contents of individual cells */ ! 1932: cdlist = (lpCellDataList) lParam; ! 1933: return (do_getdata(hwnd, cdlist)); ! 1934: ! 1935: ! 1936: case TQ_SELECT: ! 1937: /* selection has changed */ ! 1938: case TQ_ENTER: ! 1939: /* user has double-clicked or pressed enter */ ! 1940: ! 1941: pselect = (lpTableSelection) lParam; ! 1942: ! 1943: /* store location for use in later search (IDM_FCHANGE) */ ! 1944: if (pselect->nrows < 1) { ! 1945: selection = -1; ! 1946: } else { ! 1947: selection = (int) pselect->startrow; ! 1948: if (cmd == TQ_ENTER) { ! 1949: /* try to expand this row */ ! 1950: if (!ToExpand(hwnd)) { ! 1951: /* expand failed - maybe this ! 1952: * is a moved line- show the other ! 1953: * copy ! 1954: */ ! 1955: ToMoved(hwnd); ! 1956: } ! 1957: ! 1958: } ! 1959: } ! 1960: break; ! 1961: ! 1962: case TQ_CLOSE: ! 1963: /* close this table - table class no longer needs data*/ ! 1964: SvrClose(); ! 1965: break; ! 1966: ! 1967: case TQ_SCROLL: ! 1968: /* notification that the rows visible in the window ! 1969: * have changed -change the current position lines in ! 1970: * the graphic bar view (the sections picture) ! 1971: */ ! 1972: if (picture_mode) { ! 1973: BarDrawPosition(hwndBar, NULL, TRUE); ! 1974: } ! 1975: break; ! 1976: ! 1977: default: ! 1978: return(FALSE); ! 1979: } ! 1980: return(TRUE); ! 1981: } ! 1982: ! 1983: ! 1984: /*************************************************************************** ! 1985: * Function: wd_initial ! 1986: * ! 1987: * Purpose: ! 1988: * ! 1989: * Called on worker thread (not UI thread) to handle the work ! 1990: * requested on the command line. ! 1991: * arg is a pointer to a THREADARGS block allocated from gmem_get(hHeap). This ! 1992: * needs to be freed before exiting. ! 1993: */ ! 1994: DWORD ! 1995: wd_initial(LPVOID arg) ! 1996: { ! 1997: PTHREADARGS pta = (PTHREADARGS) arg; ! 1998: COMPLIST cl; ! 1999: ! 2000: ! 2001: /* build a complist from these args, ! 2002: * and register with the view we have made ! 2003: */ ! 2004: cl = complist_args(pta->first, pta->second, pta->view, pta->fDeep); ! 2005: ! 2006: if (cl == NULL) { ! 2007: view_close(pta->view); ! 2008: gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS)); ! 2009: SetNotBusy(); ! 2010: return 0; ! 2011: } ! 2012: ! 2013: ! 2014: /* if savelist was selected, write out the list and exit */ ! 2015: if(pta->savelist != NULL) { ! 2016: complist_savelist(cl, pta->savelist, pta->saveopts); ! 2017: gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS)); ! 2018: SetNotBusy(); ! 2019: exit(0); ! 2020: } ! 2021: ! 2022: /* if there was only one file, expand it */ ! 2023: if (view_getrowcount(pta->view) == 1) { ! 2024: SetSelection(0); ! 2025: ToExpand(hwndClient); ! 2026: } ! 2027: ! 2028: ! 2029: gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS)); ! 2030: SetNotBusy(); ! 2031: return(0); ! 2032: } /* wd_initial */ ! 2033: ! 2034: ! 2035: /*************************************************************************** ! 2036: * Function: wd_dirdialog ! 2037: * ! 2038: * Purpose: ! 2039: * ! 2040: * Called on worker thread (not UI thread) to handle a Dir request ! 2041: */ ! 2042: DWORD ! 2043: wd_dirdialog(LPVOID arg) ! 2044: { ! 2045: ! 2046: VIEW view = (VIEW) arg; ! 2047: ! 2048: /* make a COMPLIST using the directory dialog, ! 2049: * and notify the view ! 2050: */ ! 2051: if (complist_dirdialog(view) == NULL) { ! 2052: view_close(view); ! 2053: } ! 2054: ! 2055: /* all done! */ ! 2056: SetNotBusy(); ! 2057: return(0); ! 2058: } ! 2059: ! 2060: ! 2061: /*************************************************************************** ! 2062: * Function: wd_copy ! 2063: * ! 2064: * Purpose: ! 2065: * ! 2066: * Called on worker thread to do a copy-files operation ! 2067: */ ! 2068: DWORD ! 2069: wd_copy(LPVOID arg) ! 2070: { ! 2071: ! 2072: VIEW view = (VIEW) arg; ! 2073: ! 2074: complist_copyfiles(view_getcomplist(view), NULL, 0); ! 2075: ! 2076: SetNotBusy(); ! 2077: ! 2078: return(0); ! 2079: } ! 2080: ! 2081: ! 2082: /*************************************************************************** ! 2083: * Function: MainWndProc ! 2084: * ! 2085: * Purpose: ! 2086: * ! 2087: * Window processing for main window ! 2088: */ ! 2089: long APIENTRY ! 2090: MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam) ! 2091: { ! 2092: char str[32]; ! 2093: long ret; ! 2094: DWORD threadid; ! 2095: ! 2096: switch(message) { ! 2097: ! 2098: ! 2099: case WM_CREATE: ! 2100: ! 2101: /* initialise menu options to default/saved ! 2102: * option settings ! 2103: */ ! 2104: ! 2105: CheckMenuItem(hMenu, IDM_INCSAME, ! 2106: (outline_include & INCLUDE_SAME) ? ! 2107: MF_CHECKED:MF_UNCHECKED); ! 2108: ! 2109: CheckMenuItem(hMenu, IDM_INCLEFT, ! 2110: (outline_include & INCLUDE_LEFTONLY) ? ! 2111: MF_CHECKED:MF_UNCHECKED); ! 2112: ! 2113: CheckMenuItem(hMenu, IDM_INCRIGHT, ! 2114: (outline_include & INCLUDE_RIGHTONLY) ? ! 2115: MF_CHECKED:MF_UNCHECKED); ! 2116: CheckMenuItem(hMenu, IDM_INCDIFFER, ! 2117: (outline_include & INCLUDE_DIFFER) ? ! 2118: MF_CHECKED:MF_UNCHECKED); ! 2119: ! 2120: CheckMenuItem(hMenu, line_numbers, MF_CHECKED); ! 2121: CheckMenuItem(hMenu, expand_mode, MF_CHECKED); ! 2122: ! 2123: CheckMenuItem(hMenu, IDM_IGNBLANKS, ! 2124: ignore_blanks ? MF_CHECKED : MF_UNCHECKED); ! 2125: CheckMenuItem(hMenu, IDM_PICTURE, ! 2126: picture_mode ? MF_CHECKED : MF_UNCHECKED); ! 2127: ! 2128: /* nothing currently displayed */ ! 2129: DisplayMode = MODE_NULL; ! 2130: ! 2131: break; ! 2132: ! 2133: ! 2134: case WM_COMMAND: ! 2135: switch (GET_WM_COMMAND_ID(wParam, lParam)) { ! 2136: case IDM_EXIT: ! 2137: if (ghThread!=NULL) { ! 2138: extern CRITICAL_SECTION CSView; ! 2139: /* Stop any other thread from allocating things that we ! 2140: want to free! See the threads DOGMA at the top ! 2141: of this file. ! 2142: */ ! 2143: ! 2144: /* Because the thread that we are about to kill might be in ! 2145: a critical section, we first grab them both. It is ! 2146: essential that anyone else who ever does this, does ! 2147: so in the same order! ! 2148: */ ! 2149: WDEnter(); ! 2150: EnterCriticalSection(&CSView); ! 2151: TerminateThread(ghThread, 31); ! 2152: CloseHandle(ghThread); ! 2153: ghThread = NULL; ! 2154: LeaveCriticalSection(&CSView); ! 2155: WDLeave(); ! 2156: } ! 2157: if (!view_isexpanded(current_view)) { ! 2158: /* save the current outline size and position */ ! 2159: WINDOWPLACEMENT wp; ! 2160: if (GetWindowPlacement(hwndClient,&wp)) { ! 2161: WriteProfileInt(APPNAME, "OutlineShowCmd", wp.showCmd); ! 2162: WriteProfileInt(APPNAME, "OutlineMaxX", wp.ptMaxPosition.x); ! 2163: WriteProfileInt(APPNAME, "OutlineMaxY", wp.ptMaxPosition.y); ! 2164: WriteProfileInt(APPNAME, "OutlineNormLeft", wp.rcNormalPosition.left); ! 2165: WriteProfileInt(APPNAME, "OutlineNormTop", wp.rcNormalPosition.top); ! 2166: WriteProfileInt(APPNAME, "OutlineNormRight", wp.rcNormalPosition.right); ! 2167: WriteProfileInt(APPNAME, "OutlineNormBottom", wp.rcNormalPosition.bottom); ! 2168: WriteProfileInt(APPNAME, "OutlineSaved", 1); ! 2169: } ! 2170: } else { ! 2171: /* save the current expanded size and position */ ! 2172: WINDOWPLACEMENT wp; ! 2173: if (GetWindowPlacement(hwndClient,&wp)) { ! 2174: WriteProfileInt(APPNAME, "ExpandShowCmd", wp.showCmd); ! 2175: WriteProfileInt(APPNAME, "ExpandMaxX", wp.ptMaxPosition.x); ! 2176: WriteProfileInt(APPNAME, "ExpandMaxY", wp.ptMaxPosition.y); ! 2177: WriteProfileInt(APPNAME, "ExpandNormLeft", wp.rcNormalPosition.left); ! 2178: WriteProfileInt(APPNAME, "ExpandNormTop", wp.rcNormalPosition.top); ! 2179: WriteProfileInt(APPNAME, "ExpandNormRight", wp.rcNormalPosition.right); ! 2180: WriteProfileInt(APPNAME, "ExpandNormBottom", wp.rcNormalPosition.bottom); ! 2181: WriteProfileInt(APPNAME, "ExpandedSaved", 1); ! 2182: } ! 2183: } ! 2184: DestroyWindow(hWnd); ! 2185: break; ! 2186: ! 2187: case IDM_ABORT: ! 2188: /* abort menu item, or status bar button. ! 2189: * the status bar button text gives the appropriate ! 2190: * action depending on our state - abort, outline ! 2191: * or expand. But the command sent is always ! 2192: * IDM_ABORT. Thus we need to check the state ! 2193: * to see what to do. If we are busy, set the abort ! 2194: * flag. If there is nothing to view, ! 2195: * exit, otherwise switch outline<->expand ! 2196: */ ! 2197: if (IsBusy()) { ! 2198: bAbort = TRUE; ! 2199: SetStatus("Abort Pending"); ! 2200: ! 2201: } else if (DisplayMode == MODE_NULL) { ! 2202: DestroyWindow(hWnd); ! 2203: } else if (DisplayMode == MODE_EXPAND) { ! 2204: ToOutline(hWnd); ! 2205: } else { ! 2206: ToExpand(hWnd); ! 2207: } ! 2208: break; ! 2209: ! 2210: case IDM_FILE: ! 2211: /* select two files and compare them */ ! 2212: if (SetBusy()) { ! 2213: ! 2214: /* close the current view */ ! 2215: view_close(current_view); ! 2216: ! 2217: /* make a new empty view */ ! 2218: current_view = view_new(hwndRCD); ! 2219: ! 2220: /* make a COMPLIST using the files dialog, ! 2221: * and notify the view ! 2222: */ ! 2223: if (complist_filedialog(current_view) == NULL) { ! 2224: view_close(current_view); ! 2225: } ! 2226: ! 2227: /* all done! */ ! 2228: SetNotBusy(); ! 2229: } else { ! 2230: BusyError(); ! 2231: } ! 2232: break; ! 2233: ! 2234: case IDM_DIR: ! 2235: ! 2236: /* read two directory names, scan them and ! 2237: * compare all the files and subdirs. ! 2238: */ ! 2239: if (SetBusy()) { ! 2240: ! 2241: /* close the current view */ ! 2242: view_close(current_view); ! 2243: ! 2244: /* make a new empty view */ ! 2245: current_view = view_new(hwndRCD); ! 2246: ! 2247: ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_dirdialog, ! 2248: (LPVOID) current_view, 0, &threadid); ! 2249: ! 2250: if (ghThread == NULL) ! 2251: { ! 2252: wd_dirdialog( (LPVOID) current_view); ! 2253: } ! 2254: ! 2255: } else { ! 2256: BusyError(); ! 2257: } ! 2258: break; ! 2259: ! 2260: case IDM_CLOSE: ! 2261: /* close the output list - ! 2262: * discard all results so far ! 2263: */ ! 2264: if (!IsBusy()) { ! 2265: view_close(current_view); ! 2266: } ! 2267: break; ! 2268: ! 2269: case IDM_PRINT: ! 2270: /* print the current view - ! 2271: * either the outline list of filenames, ! 2272: * or the currently expanded file. ! 2273: */ ! 2274: if (!IsBusy()) { ! 2275: DoPrint(); ! 2276: } else { ! 2277: BusyError(); ! 2278: } ! 2279: break; ! 2280: ! 2281: case IDM_TIME: ! 2282: /* show time it took */ ! 2283: { char msg[50]; ! 2284: DWORD tim; ! 2285: if (IsBusy()) { ! 2286: BusyError(); ! 2287: } ! 2288: else{ ! 2289: tim = complist_querytime(); ! 2290: wsprintf((LPTSTR)msg, "%d.%03d seconds", tim/1000, tim%1000); ! 2291: } ! 2292: } ! 2293: break; ! 2294: ! 2295: case IDM_SAVELIST: ! 2296: /* allow user to save list of same/different files ! 2297: * to a text file. dialog box to give filename ! 2298: * and select which types of file to include ! 2299: */ ! 2300: complist_savelist(view_getcomplist(current_view), NULL, 0); ! 2301: break; ! 2302: ! 2303: case IDM_COPYFILES: ! 2304: /* ! 2305: * copy files that are same/different to a new ! 2306: * root directory. dialog box allows user ! 2307: * to select new root and inclusion options ! 2308: */ ! 2309: if (current_view == NULL) { ! 2310: MessageBox(hWnd, ! 2311: "Please create a diff list first", ! 2312: "WinDiff", MB_OK|MB_ICONSTOP); ! 2313: break; ! 2314: } ! 2315: ! 2316: if (SetBusy()) { ! 2317: ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_copy, ! 2318: (LPVOID) current_view, 0, &threadid); ! 2319: if (ghThread == NULL) ! 2320: { ! 2321: wd_copy( (LPVOID) current_view); ! 2322: } ! 2323: ! 2324: } else { ! 2325: BusyError(); ! 2326: } ! 2327: ! 2328: break; ! 2329: ! 2330: case IDM_ABOUT: ! 2331: ! 2332: DialogBox( hInst, "About", hWnd, (DLGPROC)AboutBox); ! 2333: break; ! 2334: ! 2335: /* launch an editor on the current item - left, right or ! 2336: * composite view ! 2337: */ ! 2338: case IDM_EDITLEFT: ! 2339: do_editthread(current_view, CI_LEFT); ! 2340: break; ! 2341: ! 2342: case IDM_EDITRIGHT: ! 2343: do_editthread(current_view, CI_RIGHT); ! 2344: break; ! 2345: ! 2346: case IDM_EDITCOMP: ! 2347: do_editthread(current_view, CI_COMP); ! 2348: break; ! 2349: ! 2350: /* allow customisation of the editor command line */ ! 2351: case IDM_SETEDIT: ! 2352: if (StringInput(editor_cmdline, sizeof(editor_cmdline), ! 2353: "Please enter the editor command line", ! 2354: "Windiff", editor_cmdline)) { ! 2355: WriteProfileString(APPNAME, "Editor", ! 2356: (LPCSTR)editor_cmdline); ! 2357: } ! 2358: break; ! 2359: ! 2360: ! 2361: case IDM_LNRS: ! 2362: case IDM_RNRS: ! 2363: case IDM_NONRS: ! 2364: ! 2365: /* option selects whether the line nrs displayed ! 2366: * in expand mode are the line nrs in the left ! 2367: * file, the right file or none ! 2368: */ ! 2369: ! 2370: CheckMenuItem(GetMenu(hWnd), ! 2371: line_numbers, MF_UNCHECKED); ! 2372: line_numbers = GET_WM_COMMAND_ID(wParam, lParam); ! 2373: CheckMenuItem(GetMenu(hWnd), line_numbers, MF_CHECKED); ! 2374: wsprintf((LPTSTR)str, "%d", line_numbers); ! 2375: WriteProfileString(APPNAME, "LineNumbers", str); ! 2376: ! 2377: /* change the display to show the line nr style ! 2378: * chosen ! 2379: */ ! 2380: ! 2381: view_changeviewoptions(current_view); ! 2382: ! 2383: ! 2384: break; ! 2385: ! 2386: /* ! 2387: * options selecting which files to include in the ! 2388: * outline listing, based on their state ! 2389: */ ! 2390: case IDM_INCLEFT: ! 2391: ! 2392: ! 2393: /* toggle flag in outline_include options */ ! 2394: outline_include ^= INCLUDE_LEFTONLY; ! 2395: ! 2396: /* check/uncheck as necessary */ ! 2397: CheckMenuItem(hMenu, IDM_INCLEFT, ! 2398: (outline_include & INCLUDE_LEFTONLY) ? ! 2399: MF_CHECKED:MF_UNCHECKED); ! 2400: ! 2401: wsprintf((LPTSTR)str, "%d", outline_include); ! 2402: WriteProfileString(APPNAME, "FileInclude", str); ! 2403: view_changeviewoptions(current_view); ! 2404: ! 2405: ! 2406: break; ! 2407: ! 2408: case IDM_INCRIGHT: ! 2409: ! 2410: ! 2411: outline_include ^= INCLUDE_RIGHTONLY; ! 2412: ! 2413: CheckMenuItem(hMenu, IDM_INCRIGHT, ! 2414: (outline_include & INCLUDE_RIGHTONLY) ? ! 2415: MF_CHECKED:MF_UNCHECKED); ! 2416: wsprintf((LPTSTR)str, "%d", outline_include); ! 2417: WriteProfileString(APPNAME, "FileInclude", str); ! 2418: view_changeviewoptions(current_view); ! 2419: ! 2420: break; ! 2421: ! 2422: case IDM_INCSAME: ! 2423: ! 2424: ! 2425: outline_include ^= INCLUDE_SAME; ! 2426: ! 2427: CheckMenuItem(hMenu, IDM_INCSAME, ! 2428: (outline_include & INCLUDE_SAME) ? ! 2429: MF_CHECKED:MF_UNCHECKED); ! 2430: wsprintf((LPTSTR)str, "%d", outline_include); ! 2431: WriteProfileString(APPNAME, "FileInclude", str); ! 2432: view_changeviewoptions(current_view); ! 2433: ! 2434: ! 2435: break; ! 2436: ! 2437: ! 2438: case IDM_INCDIFFER: ! 2439: ! 2440: ! 2441: ! 2442: outline_include ^= INCLUDE_DIFFER; ! 2443: ! 2444: CheckMenuItem(hMenu, IDM_INCDIFFER, ! 2445: (outline_include & INCLUDE_DIFFER) ? ! 2446: MF_CHECKED:MF_UNCHECKED); ! 2447: ! 2448: wsprintf((LPTSTR)str, "%d", outline_include); ! 2449: WriteProfileString(APPNAME, "FileInclude", str); ! 2450: view_changeviewoptions(current_view); ! 2451: ! 2452: ! 2453: break; ! 2454: ! 2455: case IDM_UPDATE: ! 2456: /* update the display. Options or files may have changed */ ! 2457: /* discard lines (thereby forcing re-read). ! 2458: */ ! 2459: file_discardlines(compitem_getleftfile( (COMPITEM)lParam) ); ! 2460: file_discardlines(compitem_getrightfile( (COMPITEM)lParam) ); ! 2461: ! 2462: view_changediffoptions(current_view); ! 2463: ! 2464: /* force repaint of bar window */ ! 2465: InvalidateRect(hwndBar, NULL, TRUE); ! 2466: break; ! 2467: ! 2468: ! 2469: ! 2470: case IDM_LONLY: ! 2471: case IDM_RONLY: ! 2472: case IDM_BOTHFILES: ! 2473: /* option selects whether the expanded file ! 2474: * show is the combined file, or just one ! 2475: * or other of the input files. ! 2476: * ! 2477: * if we are not in expand mode, this also ! 2478: * causes us to expand the selection ! 2479: */ ! 2480: ! 2481: ! 2482: CheckMenuItem(GetMenu(hWnd), expand_mode, MF_UNCHECKED); ! 2483: expand_mode = GET_WM_COMMAND_ID(wParam, lParam); ! 2484: CheckMenuItem(GetMenu(hWnd), expand_mode, MF_CHECKED); ! 2485: ! 2486: /* change the current view to show only the lines ! 2487: * of the selected type. ! 2488: */ ! 2489: if (DisplayMode == MODE_OUTLINE) { ! 2490: ToExpand(hWnd); ! 2491: } else { ! 2492: view_changeviewoptions(current_view); ! 2493: } ! 2494: ! 2495: ! 2496: break; ! 2497: ! 2498: ! 2499: case IDM_IGNBLANKS: ! 2500: ! 2501: /* if selected, ignore all spaces and tabs on ! 2502: * comparison - expand view only: outline view ! 2503: * will still show that 'text files differ' ! 2504: */ ! 2505: ! 2506: ignore_blanks = !ignore_blanks; ! 2507: CheckMenuItem(hMenu, IDM_IGNBLANKS, ! 2508: ignore_blanks? MF_CHECKED:MF_UNCHECKED); ! 2509: wsprintf((LPTSTR)str, "%d", ignore_blanks); ! 2510: WriteProfileString(APPNAME, "Blanks", str); ! 2511: ! 2512: /* invalidate all diffs since we have ! 2513: * changed diff options, and re-do and display the ! 2514: * current diff if we are in expand mode. ! 2515: */ ! 2516: view_changediffoptions(current_view); ! 2517: ! 2518: /* force repaint of bar window */ ! 2519: InvalidateRect(hwndBar, NULL, TRUE); ! 2520: ! 2521: break; ! 2522: ! 2523: case IDM_PICTURE: ! 2524: /* do we show the bar picture in expand mode ? */ ! 2525: picture_mode = !picture_mode; ! 2526: CheckMenuItem(hMenu, IDM_PICTURE, ! 2527: picture_mode? MF_CHECKED:MF_UNCHECKED); ! 2528: wsprintf((LPTSTR)str, "%d", picture_mode); ! 2529: WriteProfileString(APPNAME, "Picture", str); ! 2530: DoResize(hWnd); ! 2531: break; ! 2532: ! 2533: ! 2534: case IDM_EXPAND: ! 2535: ! 2536: /* show the expanded view of the ! 2537: * selected file ! 2538: */ ! 2539: if (current_view != NULL) { ! 2540: ToExpand(hWnd); ! 2541: } ! 2542: ! 2543: break; ! 2544: ! 2545: case IDM_OUTLINE: ! 2546: /* return to the outline view (list of filenames) */ ! 2547: ToOutline(hWnd); ! 2548: ! 2549: break; ! 2550: ! 2551: case IDM_FCHANGE: ! 2552: /* find the next line in the current view ! 2553: * that is not the same in both files - ! 2554: * in outline view, finds the next filename that ! 2555: * is not identical ! 2556: */ ! 2557: FindNextChange(); ! 2558: ! 2559: break; ! 2560: ! 2561: case IDM_FPCHANGE: ! 2562: /* same as IDM_FCHANGE, but going backwards from ! 2563: * current position ! 2564: */ ! 2565: FindPrevChange(); ! 2566: ! 2567: break; ! 2568: } ! 2569: break; ! 2570: ! 2571: case WM_SIZE: ! 2572: DoResize(hWnd); ! 2573: break; ! 2574: ! 2575: case WM_SETFOCUS: ! 2576: /* set the focus on the table class so it can process ! 2577: * page-up /pagedown keys etc. ! 2578: */ ! 2579: SetFocus(hwndRCD); ! 2580: break; ! 2581: ! 2582: case WM_KEYDOWN: ! 2583: /* although the table window has the focus, he passes ! 2584: * back to us any keys he doesn't understand ! 2585: * We handle escape here to mean 'return to outline view' ! 2586: */ ! 2587: if (wParam == VK_ESCAPE) { ! 2588: ToOutline(hWnd); ! 2589: } ! 2590: break; ! 2591: ! 2592: case WM_CLOSE: ! 2593: /* don't allow close when busy - process this message in ! 2594: * order to ensure this ! 2595: */ ! 2596: if (IsBusy()) { ! 2597: return(TRUE); ! 2598: } else { ! 2599: return(DefWindowProc(hWnd, message, wParam, lParam)); ! 2600: } ! 2601: break; ! 2602: ! 2603: case WM_DESTROY: ! 2604: ! 2605: DeleteTools(); ! 2606: PostQuitMessage(0); ! 2607: break; ! 2608: ! 2609: case TM_CURRENTVIEW: ! 2610: /* allow other people such as the bar window to query the ! 2611: * current view ! 2612: */ ! 2613: return((DWORD) current_view); ! 2614: ! 2615: default: ! 2616: /* handle registered table messages */ ! 2617: if (message == table_msgcode) { ! 2618: ret = TableServer(hWnd, wParam, lParam); ! 2619: return(ret); ! 2620: } ! 2621: return(DefWindowProc(hWnd, message, wParam, lParam)); ! 2622: } ! 2623: return(0); ! 2624: } ! 2625:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.