root/main/trunk/greenstone2/runtime-src/src/w32server/fnord.cpp @ 24498

Revision 24498, 39.5 KB (checked in by ak19, 8 years ago)

Introduced the --mode=gli command line parameter, where the gli value is used as the property prefix when retrieving autoenter and start_browser properties from the config file. These changes go towards working with a single merged server config file (glisite.cfg and llssite.cfg)

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * fnord.cpp
4 * Copyright (C) 1996
5 *
6 * A component of the fnord webserver written by bmorin@wpi.edu.
7 *
8 * Altered for use with the Greenstone digital library software by the
9 * New Zealand Digital Library Project at the University of Waikato,
10 * New Zealand.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 *********************************************************************/
27
28#include "text_t.h"
29#include <windows.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <memory.h>
34#pragma hdrstop
35#include "netio.h"
36#include "settings.h"
37#include "httpsrv.h"
38#include "resource.h"
39#include "locate.h"
40#include "cgiwrapper.h"
41#include "startbrowser.h"
42#include "d_winsock.h"
43#include "fileutil.h"
44
45#define MAINWINDOWWIDTH 400
46#define MAINWINDOWHEIGHT 200
47
48#define WASTEHEIGHT 44  // Error in ht due to caption and menu bar
49#define WASTEWIDTH 6
50#define SPACERWIDTH 5
51
52// size and position of the collection title
53#define COLTITLEWIDTH 351
54#define COLTITLEHEIGHT 35
55#define COLTITLEX ((MAINWINDOWWIDTH-COLTITLEWIDTH)/2)
56#define COLTITLEY 10
57
58// size and position of the version string
59#define VERSIONWIDTH MAINWINDOWWIDTH
60#define VERSIONHEIGHT 20
61#define VERSIONX 0
62#define VERSIONY (COLTITLEY+COLTITLEHEIGHT)
63
64// size and position of the Greenstone digital library logo
65#define LOGOWIDTH 135
66#define LOGOHEIGHT 55
67#define LOGOX (MAINWINDOWWIDTH-(LOGOWIDTH+SPACERWIDTH))
68#define LOGOY (MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))
69
70// size and position of the enter button
71#define ENTERBUTTONWIDTH 160
72#define ENTERBUTTONHEIGHT 30
73#define ENTERBUTTONX SPACERWIDTH
74#define ENTERBUTTONY ((MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))-(ENTERBUTTONHEIGHT+SPACERWIDTH))
75
76// size and position of the enter string
77#define ENTERSTRINGX (ENTERBUTTONX+ENTERBUTTONWIDTH+SPACERWIDTH)
78#define ENTERSTRINGY ENTERBUTTONY
79#define ENTERSTRINGWIDTH (MAINWINDOWWIDTH-(ENTERBUTTONWIDTH+SPACERWIDTH+SPACERWIDTH+SPACERWIDTH))
80#define ENTERSTRINGHEIGHT ENTERBUTTONHEIGHT
81
82// size and position of the info string
83#define INFOWIDTH MAINWINDOWWIDTH
84#define INFOHEIGHT (MAINWINDOWHEIGHT-INFOY)
85#define INFOX 0
86#define INFOY ENTERBUTTONY
87
88// size and position of restricted buttons
89#define ALTERNATIVEBUTTONWIDTH 160
90#define ALTERNATIVEBUTTONHEIGHT 30
91#define ALTERNATIVEBUTTONX SPACERWIDTH
92#define ALTERNATIVEBUTTONY LOGOY
93
94#define INFOBUTTONWIDTH 30
95
96// size and position of restart button
97#define RESTARTBUTTONWIDTH 160
98#define RESTARTBUTTONHEIGHT 30
99#define RESTARTBUTTONX 50
100#define RESTARTBUTTONY (MAINWINDOWHEIGHT-RESTARTBUTTONHEIGHT-15)
101
102// constant for restart/reconfigure windows message (same as in recpt/configaction.cpp)
103// http://msdn.microsoft.com/en-us/library/ms644931%28v=VS.85%29.aspx on WM_USER
104// (also RegisterWindowMessage Function at http://msdn.microsoft.com/en-us/library/ms644947%28v=VS.85%29.aspx
105// http://msdn.microsoft.com/en-us/library/ms644927%28v=VS.85%29.aspx)
106#define WM_RESTART WM_USER+1
107
108const char versionstring[] = "version " GSDL_VERSION;
109
110const char strnothing[] = "";
111const char strinit[] = "Initialising...";
112const char strsb[] = "Starting browser...";
113const char strrestartlib[] = "Press the 'Restart Library' button to start a browser\n"
114"and enter library";
115const char strenterlib[] = "Press this button to begin using\n"
116"the library";
117const char *enterstring = NULL; // points to the current enter string
118const char *infostring = NULL; // points to the current info string
119
120
121// globals to do with networking and browsers
122int have_networking = 0;
123int netscapeneeded = 0;
124char startbrowserdir[1024] = ""; // HARD LIMIT!!!!!
125
126
127// stats to do with the last time the enter library button was pressed
128// these stats are needed to make suggestions about the proxy
129int enterlib_libaccessnum = -1; // -1 = NA
130DWORD enterlib_time = 0;
131
132
133enum { undefined_window, console_window, plain_window }
134window_state;
135
136HDC coltitledc = NULL;
137HBITMAP defcoltitlebitmap = NULL, coltitlebitmap=NULL;
138
139HDC logodc=NULL;
140HBITMAP deflogobitmap=NULL, logobitmap=NULL;
141
142HWND GoButton = NULL;
143HWND Enter = NULL;
144// HWND EnterRestricted = NULL;
145// HWND InfoRestricted = NULL;
146int init_type = 0;
147int init_done = 0;
148
149
150// Added an argument so you can specify not to do any of the windows orientated clean up - jmt12 18/11/2003
151void finish_up(bool init_only) {
152  // remember the current preferences
153  write_settings("");
154
155  if(init_only) {
156    return;
157  }
158   
159 // Shutdown the HTTP server
160  EndHTTPServer();
161 
162  // Shutdown the main server modules
163  CleanUpNetIO();
164  //    RemoveFnordFromTray();
165 
166  // Unload the wsock32 dll
167  d_UnloadWinsock();
168 
169  // Clean up graphics stuff from window
170 
171  if (defcoltitlebitmap != NULL)
172    SelectObject (coltitledc, defcoltitlebitmap);
173  if (coltitlebitmap != NULL)
174    DeleteObject (coltitlebitmap);
175  if (coltitledc != NULL)
176    DeleteDC (coltitledc);
177 
178  if (deflogobitmap != NULL)
179    SelectObject (logodc, deflogobitmap);
180  if (logobitmap != NULL)
181    DeleteObject (logobitmap);
182  if (logodc != NULL)
183    DeleteDC (logodc);
184 
185  // Shutdown the main window
186  PostQuitMessage(0);
187}
188
189
190int overlap(int left, int top, int right, int bottom,
191            RECT &r2)
192{
193  if (left <= r2.right && r2.left <= right &&
194      top <= r2.bottom && r2.top <= bottom)
195    return 1;
196  else
197    return 0;
198}
199
200
201void paint_window (HDC pdc, RECT &updateRect) {
202  // make sure the various DCs are set up
203  if (coltitledc == NULL) {
204    coltitledc = CreateCompatibleDC(pdc);
205    defcoltitlebitmap = (HBITMAP)SelectObject (coltitledc, coltitlebitmap);
206  }
207 
208  if (logodc == NULL) {
209    logodc = CreateCompatibleDC(pdc);
210    deflogobitmap = (HBITMAP)SelectObject (logodc, logobitmap);
211  }
212
213  // remove any remaining sign of initial buttons
214  if (init_done && (overlap (ENTERBUTTONX, ENTERBUTTONY, ENTERBUTTONX+ENTERBUTTONWIDTH,
215        ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT, updateRect))) {
216    RECT initRect;
217    initRect.left = ENTERBUTTONX;
218    initRect.top = ENTERBUTTONY;
219    initRect.right = ENTERBUTTONX+ENTERBUTTONWIDTH;
220    initRect.bottom = ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT;
221    FillRect(pdc, &initRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
222  }
223
224  // update the collection title if needed
225  if (overlap(COLTITLEX, COLTITLEY,
226          COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT,
227          updateRect)) {
228    BitBlt (pdc, COLTITLEX, COLTITLEY,
229        COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT,
230        coltitledc, 0, 0, SRCCOPY);
231  }
232 
233  // update the version string if needed
234  if (overlap (VERSIONX, VERSIONY,
235           VERSIONX+VERSIONWIDTH, VERSIONY+VERSIONHEIGHT,
236           updateRect)) {
237    RECT versionRect;
238    versionRect.left = VERSIONX;
239    versionRect.top = VERSIONY;
240    versionRect.right = VERSIONX+VERSIONWIDTH;
241    versionRect.bottom = VERSIONY+VERSIONHEIGHT;
242    DrawText(pdc, versionstring, -1, &versionRect, DT_CENTER);
243  }
244 
245  // decide what we want to draw
246  if (init_done && gsdl_show_console) {
247    // we want to draw a "console" window
248    if (window_state != console_window ||
249    overlap (text_rect.left, text_rect.top,
250         text_rect.right, text_rect.bottom,
251         updateRect)) {
252      refresh_console (pdc);
253    }
254   
255    window_state = console_window;
256   
257  } else {
258    // we want to draw a "plain" window
259   
260    // update the enter string if needed
261    if (overlap (ENTERSTRINGX, ENTERSTRINGY, ENTERSTRINGX+ENTERSTRINGWIDTH,
262         ENTERSTRINGY+ENTERSTRINGHEIGHT, updateRect)) {
263
264    RECT enterstringRect;
265    enterstringRect.left = ENTERSTRINGX;
266    enterstringRect.top = ENTERSTRINGY;
267    enterstringRect.right = ENTERSTRINGX+ENTERSTRINGWIDTH;
268    enterstringRect.bottom = ENTERSTRINGY+ENTERSTRINGHEIGHT;
269    FillRect(pdc, &enterstringRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
270
271    if ((enterstring != NULL) && (strlen(enterstring) > 0)) {
272     
273      int cury = ENTERSTRINGY;
274      int startline = 0, here = 0;
275      while (enterstring[here] != '\0') {
276        if (enterstring[here] < ' ') {
277          if (here - startline > 0) {
278        // output the text
279        TextOut (pdc, ENTERSTRINGX, cury,
280             &enterstring[startline], here-startline);
281        cury += line_spacing;
282          }
283          startline = here+1;
284        }
285        ++here;
286      }
287      // output any remaining text
288      if (here - startline > 0) {
289        TextOut (pdc, ENTERSTRINGX, cury, &enterstring[startline], here-startline);
290      }
291    }
292    }
293   
294    window_state = plain_window;
295  }
296 
297  // update the info string if needed
298  if (init_done && !gsdl_show_console &&
299      ((infostring != NULL) && overlap (INFOX, INFOY,
300                    INFOX+INFOWIDTH, INFOY+INFOHEIGHT,
301                    updateRect))) {
302    RECT infoRect;
303    infoRect.left = INFOX;
304    infoRect.top = INFOY;
305    infoRect.right = INFOX+INFOWIDTH;
306    infoRect.bottom = INFOY+INFOHEIGHT;
307    FillRect(pdc, &infoRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
308    DrawText(pdc, infostring, -1, &infoRect, DT_CENTER);
309  }
310
311  // update the logo (always)
312  BitBlt (pdc, LOGOX, LOGOY, LOGOX+LOGOWIDTH, LOGOY+LOGOHEIGHT,
313      logodc, 0, 0, SRCCOPY);
314}
315
316
317void handle_painting (HWND Window) {
318  HDC pdc;  PAINTSTRUCT ps;
319  pdc = BeginPaint(Window, &ps);
320 
321  paint_window (pdc, ps.rcPaint);
322 
323  EndPaint(Window, &ps);
324}
325
326
327// returns 1 on success, 0 otherwise
328int enter_library (HWND Window) {
329  int res;
330 
331  if (infostring == strrestartlib) {
332
333    // the "restart library" button was pressed so we want to reinitialize
334    // greenstone, read in all the macrofiles again, etc.
335    gsdl_init(false);
336  }
337
338  // get the url and attempt to start a browser
339  if (have_networking) {
340    // There are now four address resolution methods:
341    //   0: Standard -- get local IP then resolve to a name
342    //   1: IP only -- as above, but use IP only -- don't resolve to a name
343    //   2: localhost -- always use localhost
344    //   3: 127.0.0.1 -- always use 127.0.0.1
345    char gsdl_address[100];
346    char hostIP[25]; // 16 should be enough to represent an IP address + null byte
347
348    DWORD local_ip = GetLocalIP();
349    // always work out the hostIP:
350    sprintf(hostIP, "%d.%d.%d.%d", local_ip & 0xFF, (local_ip >> 8) & 0xFF, (local_ip >> 16) & 0xFF, (local_ip >> 24) & 0xFF);
351
352    if (local_ip == INADDR_ANY || gsdl_address_resolution_method == 3) {
353      local_ip = 127 + (0 << 8) + (0 << 16) + (1 << 24);
354    }
355
356    if (gsdl_address_resolution_method == 1 || gsdl_address_resolution_method == 3) {
357      sprintf(gsdl_address, "%d.%d.%d.%d", local_ip & 0xFF, (local_ip >> 8) & 0xFF, (local_ip >> 16) & 0xFF, (local_ip >> 24) & 0xFF);
358    }
359    else if (gsdl_address_resolution_method == 2) {
360      sprintf(gsdl_address, "localhost");
361    }
362    else {
363      strcpy(gsdl_address, GetLocalName(NULL));
364    }
365
366    text_t url = "http://" + text_t(gsdl_address);
367
368    gsdl_host_IP = text_t(hostIP);
369    gsdl_url = url;
370    write_settings(gsdl_url);
371
372    if (gsdl_port_num != 80) {
373      url += ":" + text_t(gsdl_port_num);
374    }
375    url += gsdl_enterlib;
376
377    // add a unique ending so it will always result in a request
378    text_t::const_iterator it =
379      findchar (gsdl_enterlib.begin(), gsdl_enterlib.end(), '?');
380    if (it == gsdl_enterlib.end()) url.push_back ('?');
381    else url.push_back ('&');
382    int tcount = GetTickCount();
383    url += "uq=" + text_t(tcount);
384   
385    // remember the library access number for later proxy checking
386    enterlib_libaccessnum = libaccessnum;
387   
388    if (gsdl_start_browser) {
389
390      // do a quick check to make sure we're using netscape when
391      // we should be (it might have been just installed)
392      if (netscapeneeded) gsdl_check_browser_settings (netscapeneeded);
393   
394      char *cstr_url = url.getcstr();
395      if (strlen (startbrowserdir) <= 0) {
396    res = startbrowser (cstr_url, gsdl_browser_exe, NULL);
397   
398      } else res = startbrowser (cstr_url, gsdl_browser_exe, startbrowserdir);
399   
400      delete []cstr_url;
401
402    } else {
403      return 1;
404    }
405  }
406 
407  if (res == SB_NOERROR) {
408    // success !!
409   
410    // remember the time the browser was started for later proxy checking
411    if (have_networking) enterlib_time = GetTickCount();
412   
413    return 1;
414  }
415 
416  // no browser was started
417  enterlib_libaccessnum = -1;
418 
419  if ((res == SB_FAIL_BADFORMAT) || (res == SB_FAIL_NOTFOUND)) {
420    if (!netscapeneeded) { // any browser
421      MessageBox(Window,
422         "Failed to start your chosen browser. It seems that your\n"
423         "chosen browser has been removed or corrupted.\n"
424         "Please check your browser choice by going to the\n"
425         "'Settings...' item under the 'File' menu.",
426         "Greenstone Digital Library Software", MB_OK);
427    } else { // netscape used
428      MessageBox(Window,
429         "Failed to start Netscape. It seems that Netscape has\n"
430         "been removed or corrupted. You need Netscape\n"
431         "installed to use the Greenstone Digital Library\n"
432         "software on non-networked machines.",
433         "Greenstone Digital Library Software", MB_OK);
434    }
435   
436  } else {
437    MessageBox(Window,
438           "Failed to start your browser. This may have been\n"
439           "because there was not enough memory available. Shut\n"
440           "down all other applications you have running, and\n"
441           "try again.",
442           "Greenstone Digital Library Software", MB_OK);
443  }
444 
445  return 0; // failed
446}
447
448
449void install_netscape (HWND Window) {
450  char installpath[256];
451 
452  // try to find the browser directory
453  char *gsdlhome = gsdl_gsdlhome.getcstr();
454  strcpy (installpath, gsdlhome); // use gsdlhome to find the CD-ROM drive...
455  delete []gsdlhome;
456 
457  // remove any slashes from the pathname
458  int len = strlen (installpath);
459  while ((len > 0) && ((installpath[len-1] == '\\') || (installpath[len-1] == '/'))) {
460    --len;
461  }
462  // remove '\gsdl'
463  len = len - 5;
464  installpath[len] = '\0';
465 
466  strcat (installpath, "\\netscape\\");
467 
468  // check this directory
469  if (!cstrcheckdir(installpath)) {
470    return;
471  }
472 
473  // get the operating system information
474  OSVERSIONINFO osver;
475  memset(&osver, 0, sizeof(OSVERSIONINFO));
476  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
477  GetVersionEx(&osver);
478
479  // get the install program for this operating system
480  if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
481    strcat (installpath, "n16e405.exe");
482  } else {
483    strcat (installpath, "n32e405.exe");
484  }
485 
486  // run the install program
487  int res = WinExec (installpath, SW_SHOW);
488  if (res == 0) {
489    // out of resources or memory
490    MessageBox (Window,
491        "Did not have enough resources or memory to run the\n"
492        "install program. Try shutting down all other programs\n"
493        "and trying again.",
494        "Greenstone Digital Library Software",
495        MB_OK|MB_APPLMODAL);
496   
497  } else if (res == ERROR_BAD_FORMAT) {
498    // executable image is corrupt -- ????
499    MessageBox (Window,
500        "The install program seems to be corrupt.",
501        "Greenstone Digital Library Software",
502        MB_OK|MB_APPLMODAL);
503   
504  } else if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) {
505    // couldn't find the executable -- ????
506    MessageBox (Window,
507        "Could not find the install program. Try installing\n"
508        "Netscape from the Greenstone Digital Library\n"
509        "software's install program.",
510        "Greenstone Digital Library Software",
511        MB_OK|MB_APPLMODAL);
512  }
513}
514
515void open_help () {
516  char topdir[256], cmd[256];
517 
518  // try to find the browser directory
519  char *gsdlhome = gsdl_gsdlhome.getcstr();
520  strcpy (topdir, gsdlhome); // use gsdlhome to find the CD-ROM drive...
521  delete []gsdlhome;
522  strcpy (cmd, "notepad ");
523 
524  // remove any slashes from the pathname
525  int len = strlen (topdir);
526  while ((len > 0) && ((topdir[len-1] == '\\') || (topdir[len-1] == '/'))) {
527    --len;
528  }
529  // remove the '\gsdl'
530  len = len - 5;
531  topdir[len] = '\0';
532
533  strcat (topdir, "\\README.txt");
534  strcat (cmd, topdir);
535 
536  WinExec (cmd, SW_SHOW);
537}
538
539
540long __stdcall WndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
541  switch(Message) {
542    // Constant Messages
543  case WM_CREATE:
544    break;
545   
546  case WM_COMMAND:
547    if ((GoButton != NULL) && ((HWND)LParam == GoButton)) {
548      // attempt to start a browser
549      gsdl_start_browser = 1;
550      if (enter_library (Window) && !gsdl_show_console)
551        ShowWindow(Window,SW_MINIMIZE);
552
553    } else if ((Enter != NULL) && ((HWND)LParam == Enter)) {
554      init_done = 1;
555      init_type = 1;
556
557//      } else if ((EnterRestricted != NULL) && ((HWND)LParam == EnterRestricted)) {
558//        init_done = 1;
559//        init_type = 0;
560
561//      } else if ((InfoRestricted != NULL) && ((HWND)LParam == InfoRestricted)) {
562//        MessageBox (NULL, "The Greenstone system automatically determines whether your computer has\n"
563//            "network software installed or is connected to a network.  It operates correctly\n"
564//            "under any of these conditions.\n\n"
565//            "The restricted version is intended for use when the standard one\n\n"
566//            "   (a) causes an unwanted telephone dialup operation;\n"
567//            "   (b) fails to run because network software is installed, but installed\n"
568//            "         incorrectly.\n\n"
569//            "The restricted version only works with Netscape (not Internet Explorer).\n\n"
570//            "Unless these problems arise, you should always use the standard version\n"
571//            "(press the 'Enter Library' button).\n",
572//            "Greenstone Digital Library Software",
573//            MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
574
575    } else {
576      switch (LOWORD(WParam)) {
577      case ID_PROJECT_SETTINGS:
578    Settings_Dialog(Window, netscapeneeded);
579    break;
580      case ID_INSTALL_NETSCAPE:
581    install_netscape(Window);
582    break;
583      case IDHELP:
584    open_help();
585    break;
586      case ID_PROJECT_EXIT:
587        finish_up(false);
588        break;
589      default:
590        break;
591      }
592    }
593    break;
594   
595  case WM_PAINT:
596    handle_painting(Window);
597    break;
598   
599  case HTTP_SERVER_MSG:
600    ProcessHTTPServerMsg(WParam, LParam);
601    break;
602   
603  case WM_DESTROY:
604    finish_up(false);
605    break;
606   
607  default:
608    //Unhandled Messages end up here (DefWindowProc)
609    return DefWindowProc(Window, Message, WParam, LParam);
610  }
611 
612  return(0);
613}
614
615// returns 0 if successful,
616// otherwise a WSA error number
617int tryinitnetwork (HANDLE Instance, HWND MsgWindow, char *path) {
618  // try to load winsock
619  int err = d_LoadWinsock (path);
620 
621  if (err == D_NOERROR) {
622    // next, try to init netio
623    err = InitNetIO();
624   
625    if (err == 0) {
626      // next, try to start the http server
627      err = StartHTTPServer(MsgWindow);
628     
629      if (err == 0) {
630    // finally, get the host name (no error value
631    // is returned from this function)
632    GetLocalName((HINSTANCE)Instance);
633   
634      } else {
635    // couldn't start the http server,
636    // deinit netio and unload winsock
637    CleanUpNetIO();
638    d_UnloadWinsock();
639      }
640     
641    } else {
642      // couldn't init netio, unload winsock
643      d_UnloadWinsock();
644    }
645   
646  } else {
647    // couldn't load winsock
648    err = WSASYSNOTREADY;
649  }
650 
651  return err;
652}
653
654
655// inits all the network functionality
656// returns 0 if an unrecoverable error occurred,
657// and 1 if everything successfully initialised.
658int initnetwork (HANDLE Instance, HWND MsgWindow) {
659  OSVERSIONINFO osver;
660 
661  // get the operating system information
662  memset(&osver, 0, sizeof(OSVERSIONINFO));
663  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
664  GetVersionEx(&osver);
665 
666  // first try to initialise the network with system installed
667  // networking software
668  startbrowserdir[0] = '\0';
669  netscapeneeded = 0;
670  int err = 1;
671  if (init_type == 1) err = tryinitnetwork (Instance, MsgWindow, NULL);
672 
673  // if an error occurred, try again with billsock
674  if (err != 0) {
675    // get the path of billsock (current directory + ("net16" | "net32"))
676    char winsockpath[1024]; // HARD LIMIT!!!!
677   
678    find_location();
679    char *data_location_c = data_location.getcstr();
680    strcpy (winsockpath, data_location_c);
681    delete []data_location_c;
682   
683    // remove all the slashes at the end of billpath
684    int len = strlen (winsockpath);
685    while ((len > 0) && ((winsockpath[len-1] == '\\') || (winsockpath[len-1] == '/'))) {
686      --len;
687    }
688    winsockpath[len] = '\0';
689   
690    if (osver.dwPlatformId == VER_PLATFORM_WIN32s)
691      strcat (winsockpath, "\\net16\\");
692    else {
693      strcat (winsockpath, "\\net32\\");
694      strcpy (startbrowserdir, winsockpath);
695    }
696   
697    // try again
698    err = tryinitnetwork (Instance, MsgWindow, winsockpath);
699   
700    if (err == 0) {
701      // we will need to use netscape on 95/98/NT machines
702      if (osver.dwPlatformId != VER_PLATFORM_WIN32s) {
703    netscapeneeded = 1;
704    // make sure the browser state is in step with the network condition
705    gsdl_check_browser_settings (netscapeneeded);
706      }
707     
708      // check to see if a browser is running
709      if (browserrunning(gsdl_browser_exe) == NO_ERROR) {
710    MessageBox (NULL,
711            "The Greenstone Digital Library software has detected a\n"
712            "running browser. To let our networking software\n"
713            "correctly initialize, please shut down your browser\n"
714            "and restart the Greenstone Digital Library software.",
715            "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL);
716    PostMessage(MsgWindow,WM_CLOSE,0,0);
717    finish_up(false); // will unload winsock
718    exit(0);      // nothing more to do
719      }
720    }
721  }
722 
723  // if an error occurred display a nice error message
724  if (err != 0) {
725   
726    // WSASYSNOTREADY   Couldn't load winsock
727    // WSAVERNOTSUPPORTED   The version of Windows Sockets support requested
728    //          is not provided by this particular Windows Sockets implementation.
729    // WSAEINVAL    The Windows Sockets version specified by the application
730    //          is not supported by this DLL.
731    // WSAEPROTONOSUPPORT   The specified protocol is not supported.
732    // WSAEPROTOTYPE    The specified protocol is the wrong type for this socket.
733    // WSAESOCKTNOSUPPORT   The specified socket type is not supported in
734    //      this address family.
735    // WSANOTINITIALISED    A successful WSAStartup must occur before
736    //      using this function.
737    // WSAENETDOWN  The Windows Sockets implementation
738    //      has detected that the network subsystem has failed.
739    // WSAEADDRINUSE    The specified address
740    //      is already in use. (See the SO_REUSEADDR socket option under setsockopt.)
741    // WSAEFAULT    The namelen argument is too small (less
742    //      than the size of a struct sockaddr).
743    // WSAEINPROGRESS   A blocking Windows Sockets call is in progress.
744    // WSAEAFNOSUPPORT  The specified address family is not supported
745    //      by this protocol.
746    // WSAENOBUFS   Not enough buffers available, too many connections.
747    // WSAENOTSOCK  The descriptor is not a socket.
748    // WSAEISCONN   The socket is already connected.
749    // WSAEMFILE    No more file descriptors are available.
750    // WSAEOPNOTSUPP    The referenced socket is not of a type that
751    //      supports the listen operation.
752   
753    // get a text version of the error number
754    char errstr[256];
755   
756    switch (err) {
757    case WSASYSNOTREADY: strcpy(errstr, "WSASYSNOTREADY");
758      break;
759    case WSAVERNOTSUPPORTED: strcpy (errstr, "WSAVERNOTSUPPORTED");
760      break;
761    case WSAEINVAL: strcpy (errstr, "WSAEINVAL");
762      break;
763    case WSAEPROTONOSUPPORT: strcpy (errstr, "WSAEPROTONOSUPPORT");
764      break;
765    case WSAEPROTOTYPE: strcpy (errstr, "WSAEPROTOTYPE");
766      break;
767    case WSAESOCKTNOSUPPORT: strcpy (errstr, "WSAESOCKTNOSUPPORT");
768      break;
769    case WSANOTINITIALISED: strcpy (errstr, "WSANOTINITIALISED");
770      break;
771    case WSAEFAULT: strcpy (errstr, "WSAEFAULT");
772      break;
773    case WSAEAFNOSUPPORT: strcpy (errstr, "WSAEAFNOSUPPORT");
774      break;
775    case WSAENOTSOCK: strcpy (errstr, "WSAENOTSOCK");
776      break;
777    case WSAEISCONN: strcpy (errstr, "WSAEISCONN");
778      break;
779    case WSAEOPNOTSUPP: strcpy (errstr, "WSAEOPNOTSUPP");
780      break;
781    case WSAENETDOWN: strcpy (errstr, "WSAENETDOWN");
782      break;
783    case WSAEADDRINUSE: strcpy (errstr, "WSAEADDRINUSE");
784      break;
785    case WSAEINPROGRESS: strcpy (errstr, "WSAEINPROGRESS");
786      break;
787    case WSAENOBUFS: strcpy (errstr, "WSAENOBUFS");
788      break;
789    case WSAEMFILE: strcpy (errstr, "WSAEMFILE");
790      break;
791    default: sprintf (errstr, "WSA ERROR: %i", err);
792      break;
793    }
794   
795    // create a nice error message
796    char message[2048];
797   
798    switch (err) {
799    case WSAEADDRINUSE:
800      // couldn't bind socket
801      sprintf (message, "Could not find a free socket.", errstr);
802      break;
803     
804    default:
805      // cannot init winsock
806      sprintf (message, "Could not initialize the network\n"
807           " (Reason: %s).", errstr);
808      break;
809    }
810   
811    strcat (message, "\n\n"
812        "Please submit a bug report using the support.htm file\n"
813        "on the CD-ROM.");
814   
815    MessageBox (NULL, message, "Greenstone Digital Library Software", MB_OK);
816  }
817 
818  return (err == 0);
819}
820
821
822void log_computer_info () {
823  char tmpstr[1024];
824 
825  // get various information about this computer
826  if (gsdl_keep_log || gsdl_show_console) {
827    // get operating system information
828    OSVERSIONINFO osver;
829    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
830   
831    if (GetVersionEx(&osver)) {
832      if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
833    log_message ("Platform: win32s\n");
834      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
835    log_message ("Platform: windows 95\n");
836      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
837    log_message ("Platform: windows NT\n");
838      }
839     
840      sprintf (tmpstr, "MajorVersion: %i\n", (int)osver.dwMajorVersion);
841      log_message(tmpstr);
842      sprintf (tmpstr, "MinorVersion: %i\n", (int)osver.dwMinorVersion);
843      log_message(tmpstr);
844      sprintf (tmpstr, "BuildNumber: %i\n", (int)osver.dwBuildNumber);
845      log_message(tmpstr);
846      sprintf (tmpstr, "CSDVersion: %s\n\n", osver.szCSDVersion);
847      log_message(tmpstr);
848    }
849   
850    // get memory information
851    MEMORYSTATUS memstatus;
852    memstatus.dwLength = sizeof(MEMORYSTATUS);
853    GlobalMemoryStatus(&memstatus);
854   
855    sprintf (tmpstr, "TotalPhys: %i Meg\n", (int)(memstatus.dwTotalPhys/1024/1024));
856    log_message (tmpstr);
857    sprintf (tmpstr, "AvailPhys: %i Meg\n", (int)(memstatus.dwAvailPhys/1024/1024));
858    log_message (tmpstr);
859    sprintf (tmpstr, "TotalPageFile: %i Meg\n", (int)(memstatus.dwTotalPageFile/1024/1024));
860    log_message (tmpstr);
861    sprintf (tmpstr, "AvailPageFile: %i Meg\n", (int)(memstatus.dwAvailPageFile/1024/1024));
862    log_message (tmpstr);
863    sprintf (tmpstr, "TotalVirtual: %i Meg\n", (int)(memstatus.dwTotalVirtual/1024/1024));
864    log_message (tmpstr);
865    sprintf (tmpstr, "AvailVirtual: %i Meg\n\n", (int)(memstatus.dwAvailVirtual/1024/1024));
866    log_message (tmpstr);
867   
868    // log the version number
869    log_message("GSDL version: " GSDL_VERSION "\n");
870  }
871 
872}
873
874// possible command line options are
875// --location=directory (the path to GSDLHOME which defaults to the
876// directory where server.exe lives)
877// --mode=gli (when server.exe is run from GLI). If GLI, "gli." is
878// the prefix used to load autoenter and start_browser properties
879// (gli.autoenter, gli.start_browser) from the config file
880// --config=file (the path to the configuration file to use which defaults
881// to GSDLHOME\llssite.cfg)
882// --cmd=init  Used to initialize the llssite.cfg file only - jmt12 18/11/2003
883static void parse_args(const text_t cmdline, text_t &location, text_t &mode, text_t &config_file, text_t &command) {
884
885  location.clear();
886  config_file.clear();
887  mode.clear();
888  command.clear(); // jmt12 18/11/2003
889
890  if (cmdline.size() < 4) return;
891
892  text_t name, val;
893  bool foundname = false;
894  text_t::const_iterator here = cmdline.begin();
895  text_t::const_iterator end = cmdline.end();
896  while (here != end) {
897    if (*here == '-' && ((here+1) != end) && (*(here+1) == '-')) {
898      ++here;
899      if (name == "location") {
900    location = val;
901      } else if(name == "mode") {
902    mode = val;
903      } else if (name == "config") {
904    config_file = val;
905      } else if(name == "cmd") { // jmt12 18/11/2003
906    command = val;
907      }
908      foundname = false;
909      name.clear();
910      val.clear();
911    } else if (*here == '=') {
912      foundname = true;
913    } else {
914      if (foundname) {
915    val.push_back(*here);
916      } else {
917    name.push_back(*here);
918      }
919    }
920    ++here;
921  }
922  if (name == "location") {
923    location = val;
924  } else if (name == "mode") {
925    mode = val;
926  } else if (name == "config") {
927    config_file = val;
928  } else if(name == "cmd") { // jmt12 18/11/2003
929    command = val;
930  }
931}
932
933
934// Tries to generate llssite.cfg from llssite.cfg.in in directory given
935// by location variable (assumes location is GSDLHOME), if llsite.cfg is missing
936void ensure_llssite_cfg(const text_t location) {
937  text_t configfile = location+"\llssite.cfg";
938  text_t configtemplate = location+"\llssite.cfg.in";
939
940  if(!file_exists (configfile)) {
941   
942    if(file_exists (configtemplate)) {
943      // try creating llssite.cfg from the template configfile llssite.cfg.in
944      // by using a straightforward copy
945      file_copy(configtemplate, configfile);
946    }
947  }
948}
949
950
951// Added code to allow for an 'init' run of the server which just creates the llssite.cfg file
952int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
953  HWND MainWindow;  MSG Message;  WNDCLASS MainClass; 
954
955  // One instance of the local library server is quite enough, thank you very much
956  HWND gw = FindWindow("Greenstone Digital Library Software",
957               "Greenstone Digital Library Software");
958  if (gw != NULL) {
959    exit(1);
960  }
961
962  // parse arguments
963  text_t location, mode, config_file, command;
964  parse_args(CmdLineStr, location, mode, config_file, command);
965  gsdl_conffile = config_file;
966  if (mode.empty()) {
967    // if the server is run on its own, mode_prefix is "" with no '.' suffix
968    gsdl_mode_property_prefix = "";
969  } else {
970    // if the server is launched from GLI, the mode_prefix is "gli" and needs
971    // '.' suffixed when accessing certain properties from the config file.     
972    gsdl_mode_property_prefix = mode + ".";
973  }
974 
975  // Try to generate the llssite.cfg file if it's missing
976  ensure_llssite_cfg(location);
977
978  // jmt12 18/11/2003
979  if(command == "init") {
980    // init various modules
981    read_settings(0); // don't know if netscape is needed at this point
982    finish_up(true);
983    exit(0);
984  }
985
986  //Create a window class
987  MainClass.style = CS_HREDRAW | CS_VREDRAW;
988  MainClass.lpfnWndProc = WndProc;
989  MainClass.cbClsExtra = 0;
990  MainClass.cbWndExtra = 0;
991  MainClass.hInstance = Instance;
992  MainClass.hIcon     = LoadIcon(Instance, MAKEINTRESOURCE(TRAY_ICON));
993  MainClass.hCursor   = LoadCursor(NULL, IDC_ARROW);
994  MainClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
995  MainClass.lpszMenuName = MAKEINTRESOURCE(Main_Menu);
996  MainClass.lpszClassName = "Greenstone Digital Library Software";
997  if (!RegisterClass(&MainClass))
998    return 0;
999 
1000 
1001  // Load various bitmaps
1002  coltitlebitmap = LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_COL_TITLE));
1003  logobitmap= LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_LOGO));
1004 
1005  // Create the main window
1006  MainWindow = CreateWindow("Greenstone Digital Library Software",
1007                "Greenstone Digital Library Software",
1008                WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
1009                WS_MINIMIZEBOX,
1010                CW_USEDEFAULT, CW_USEDEFAULT,
1011                MAINWINDOWWIDTH + WASTEWIDTH,
1012                MAINWINDOWHEIGHT + WASTEHEIGHT,
1013                NULL, NULL, Instance, NULL);
1014 
1015  text_rect.left = 0; 
1016  text_rect.top = VERSIONY+VERSIONHEIGHT + 5;
1017  text_rect.right = MAINWINDOWWIDTH;
1018  text_rect.bottom = LOGOY-SPACERWIDTH;
1019 
1020  window_state = undefined_window;
1021 
1022  ShowWindow(MainWindow, SW_SHOW);
1023  set_location(location);
1024 
1025  // get ready to draw the main window
1026  RECT windowRect;
1027  GetClientRect (MainWindow, &windowRect);
1028  HDC pdc = GetDC (MainWindow);
1029 
1030  // retrieve and save the text metrics
1031  TEXTMETRIC tm;
1032  GetTextMetrics(pdc, &tm);
1033  line_spacing = tm.tmHeight + tm.tmExternalLeading;
1034  GSDL_Window = MainWindow; 
1035
1036  // init various modules
1037  read_settings (0); // don't know if netscape is needed at this point
1038 
1039  if (!gsdl_auto_enter) {
1040   
1041    // add the select version checkbox
1042    Enter = CreateWindow("BUTTON",             // predefined class
1043             "Enter Library",      // button text
1044             WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_DEFPUSHBUTTON,  // styles
1045             ENTERBUTTONX,         // starting x position
1046             ENTERBUTTONY,         // starting y position
1047             ENTERBUTTONWIDTH,     // button width
1048             ENTERBUTTONHEIGHT,    // button height
1049             MainWindow,           // parent window
1050             NULL,                 // No menu
1051             Instance,
1052             NULL);                // pointer not needed
1053   
1054//      EnterRestricted = CreateWindow("Button",                // predefined class
1055//                     "Restricted Version",    // button text
1056//                     WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON,   // styles
1057//                     ALTERNATIVEBUTTONX,      // starting x position
1058//                     ALTERNATIVEBUTTONY,      // starting y position
1059//                     ALTERNATIVEBUTTONWIDTH-(INFOBUTTONWIDTH+SPACERWIDTH),  // button width
1060//                     ALTERNATIVEBUTTONHEIGHT, // button height
1061//                     MainWindow,              // parent window
1062//                     (HMENU)NULL,             // No menu
1063//                     Instance,
1064//                     NULL);                   // pointer not needed
1065   
1066//      InfoRestricted = CreateWindow("Button",                // predefined class
1067//                    NULL,
1068//                    WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_BITMAP,   // styles
1069//                    ALTERNATIVEBUTTONWIDTH-INFOBUTTONWIDTH+SPACERWIDTH, // starting x position
1070//                    ALTERNATIVEBUTTONY,      // starting y position
1071//                    INFOBUTTONWIDTH,         // button width
1072//                    ALTERNATIVEBUTTONHEIGHT, // button height
1073//                    MainWindow,              // parent window
1074//                    (HMENU)NULL,             // No menu
1075//                    Instance,
1076//                    NULL);                   // pointer not needed
1077   
1078//      HANDLE i_icon = LoadImage (Instance, MAKEINTRESOURCE(GSDL_ICBMP), IMAGE_BITMAP,
1079//                     INFOBUTTONWIDTH-4, ALTERNATIVEBUTTONHEIGHT-4, LR_DEFAULTCOLOR);
1080//      SendMessage (InfoRestricted, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)i_icon);
1081   
1082    SetFocus (Enter);
1083       
1084    // Since we have not entered the library yet, set the URL in the configfile to pending state
1085    gsdl_url = "URL_pending";
1086    write_settings(gsdl_url);
1087
1088    enterstring = strenterlib;
1089    paint_window (pdc, windowRect);
1090   
1091    // message loop for init buttons
1092    while (!init_done) {
1093      if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
1094        if (Message.message == WM_QUIT) return Message.wParam;
1095        if (!IsDialogMessage (MainWindow, &Message)) {
1096            TranslateMessage(&Message); /* translate keyboard messages */
1097            DispatchMessage(&Message);  /* return control to Windows NT */
1098        }
1099      } else {
1100        Sleep (1);
1101      }
1102    }
1103   
1104    // don't want these buttons anymore
1105    DestroyWindow (Enter);
1106    // DestroyWindow (EnterRestricted);
1107    // DestroyWindow (InfoRestricted);
1108   
1109    enterstring = strnothing;
1110    paint_window (pdc, windowRect);
1111   
1112  } else {
1113    // auto enter is enabled - start up standard version
1114    init_type = 1;
1115    init_done = 1;
1116  }
1117 
1118  // draw the main window containing an init message
1119  infostring = strinit;
1120  paint_window (pdc, windowRect);
1121  DWORD lastcheck = GetTickCount();
1122 
1123  have_networking = initnetwork (Instance, MainWindow);
1124  if (!have_networking) {
1125    MessageBox(NULL,
1126           "Failed to initialize networking.",
1127           "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);
1128    exit (0);
1129  }
1130
1131  if (!gsdl_init()) // quit if can't initialise the library correctly
1132    exit (0);
1133  initstartbrowser();
1134  log_computer_info ();
1135 
1136  // show the initialising message for at least 1 second
1137  while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) {
1138    Sleep (1);
1139  }
1140 
1141  // attempt to start a browser
1142  if (gsdl_show_console || !gsdl_start_browser) infostring = strnothing;
1143  else infostring = strsb;
1144  paint_window (pdc, windowRect);
1145  lastcheck = GetTickCount();
1146  if (enter_library (MainWindow) && !gsdl_show_console) {
1147    // stay maximised for at least 1 second
1148    while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) Sleep (1);
1149    ShowWindow(MainWindow,SW_MINIMIZE);
1150  }
1151 
1152  // add the "restart library" button
1153  GoButton = CreateWindow("BUTTON",              // predefined class
1154              "Restart Library",     // button text
1155              WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // styles
1156              RESTARTBUTTONX,        // starting x position
1157              RESTARTBUTTONY,        // starting y position
1158              RESTARTBUTTONWIDTH,    // button width
1159              RESTARTBUTTONHEIGHT,   // button height
1160              MainWindow,            // parent window
1161              NULL,                  // No menu
1162              Instance,
1163              NULL);                 // pointer not needed
1164 
1165  infostring = strrestartlib;
1166  paint_window (pdc, windowRect);
1167 
1168  // release the DC used to display the init messages
1169  ReleaseDC (MainWindow, pdc);
1170 
1171  //Message loop
1172  lastcheck = GetTickCount();
1173  int seenbrowser = 0;  // if we see a browser then it disappears
1174                        // we will ask if they want to close the
1175                        // the library down
1176  char last_gsdl_browser_exe[MAX_FILENAME_SIZE]; // need to notice when the
1177                                                 // browser setting changes
1178  strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
1179 
1180  for (;;) {
1181    if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
1182        if (Message.message == WM_QUIT) {
1183            break;
1184        }
1185       
1186        if (Message.message == WM_RESTART) {
1187           
1188            read_settings(0);
1189            if (!gsdl_init(false)) { // do the same as when restart library is pressed
1190                MessageBox(NULL,"Error re-initializing gsdl: gsdl_init()",
1191                    "Error initialising GSDL", MB_OK|MB_SYSTEMMODAL);
1192                // when Restart Library is pressed, exit(0) is called) but a break here
1193                // will exit Greenstone same as with WM_QUIT msg above
1194                break;
1195            }           
1196        }
1197       
1198        if (!IsDialogMessage (MainWindow, &Message)) {
1199            TranslateMessage(&Message); /* translate keyboard messages */
1200            DispatchMessage(&Message);  /* return control to Windows NT */
1201        } 
1202    } else {
1203      if (DiffTickCounts (lastcheck, GetTickCount()) > 500) {
1204    // make sure the browser hasn't changed
1205    if (strcmp (last_gsdl_browser_exe, gsdl_browser_exe) != 0) {
1206      seenbrowser = 0;
1207      strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
1208    }
1209   
1210    // do check
1211    lastcheck = GetTickCount();
1212    if (gsdl_start_browser && browserrunning(gsdl_browser_exe) == NO_ERROR) {
1213      // we were able to connect to a browser
1214      seenbrowser = 1;
1215     
1216      // see if the enter library button has been pressed
1217      // with nothing happening for 20 seconds
1218      if ((enterlib_libaccessnum >= 0) &&
1219          (enterlib_libaccessnum == libaccessnum) &&
1220          (DiffTickCounts (enterlib_time, GetTickCount()) > 20000)) {
1221        // something could be wrong!! (most likely cause is a proxy)
1222        MessageBox(NULL,
1223               "Your browser does not seem to be responding to the 'Enter Library'\n"
1224               "request. Try turning off all proxy servers in your browser settings.\n"
1225               "If you are using Internet Explorer make sure BOTH dialup settings\n"
1226               "AND LAN settings have their proxy servers disabled.",
1227               "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);
1228        enterlib_libaccessnum = -1;
1229      }
1230     
1231     
1232    } else {
1233      // no browser was found
1234     
1235      if (seenbrowser) {
1236        // we have seen a browser in the past
1237        if (MessageBox(NULL,
1238               "The Greenstone Digital Library software has noticed that you\n"
1239               "shut down your browser. Would you also like to shut down the\n"
1240               "Greenstone Digital Library software?",
1241               "Greenstone Digital Library Software",MB_YESNO|MB_SYSTEMMODAL) == IDYES)
1242          PostMessage(MainWindow,WM_CLOSE,0,0);
1243      }
1244      seenbrowser = 0;
1245    }
1246      }
1247     
1248      Sleep (1); // millisecond
1249    }
1250  }
1251 
1252  return Message.wParam;
1253}
1254
Note: See TracBrowser for help on using the browser.