/[winpt]/trunk/Src/WinPT.cpp
ViewVC logotype

Diff of /trunk/Src/WinPT.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 102 by twoaday, Tue Nov 29 08:56:21 2005 UTC revision 159 by twoaday, Wed Jan 18 13:57:31 2006 UTC
# Line 1  Line 1 
1  /* WinPT.cpp - Windows Privacy Tray (WinPT)  /* WinPT.cpp - Windows Privacy Tray (WinPT)
2   *      Copyright (C) 2000-2005 Timo Schulz   *      Copyright (C) 2000-2006 Timo Schulz
3   *   *
4   * This file is part of WinPT.   * This file is part of WinPT.
5   *   *
# Line 22  Line 22 
22  #endif  #endif
23    
24  #include <windows.h>  #include <windows.h>
25    #include <shlobj.h>
26    
27  #include "resource.h"  #include "resource.h"
28  #include "wptTypes.h"  #include "wptTypes.h"
# Line 40  Line 41 
41  #include "wptCardEdit.h"  #include "wptCardEdit.h"
42  #include "wptCrypto.h"  #include "wptCrypto.h"
43    
 #define MIN_GPG_VER   "1.4.2"   /* Minimal GPG version. */  
 #define MIN_GPGME_VER "1.2.0"   /* Minimal GPGME version. */  
   
44    
45  HINSTANCE glob_hinst;   /* global instance for the dialogs */  HINSTANCE glob_hinst;   /* global instance for the dialogs */
46  HWND glob_hwnd;         /* global window handle for the dialogs */  HWND glob_hwnd;         /* global window handle for the dialogs */
47  HWND activ_hwnd;  HWND activ_hwnd;
 LOCK mo_file;  
48  int scard_support = 0;  int scard_support = 0;
49  int debug = 0;  int debug = 0;
50  int mobile = 0;  int mobile = 0;
# Line 96  static void Line 93  static void
93  load_gettext (int prev_inst)  load_gettext (int prev_inst)
94  {  {
95      char *nls = NULL;      char *nls = NULL;
     char *file = NULL;  
96    
97      nls = get_gettext_lang ();      nls = get_gettext_lang ();
98      if (nls) {      if (nls != NULL) {
99          set_gettext_file ("winpt", nls);          set_gettext_file ("winpt", nls);
         file = make_filename (nls, "winpt", "mo");  
         if (!file_exist_check (nls) && init_file_lock (&mo_file, file))  {  
             if (!prev_inst)  
                 msg_box (NULL, _("Could not initizalize file lock.\n"  
                                  "Native Language Support"),  
                          _("WinPT Error"), MB_ERR);  
         }  
100          free_if_alloc (nls);          free_if_alloc (nls);
         free_if_alloc (file);  
101      }      }
102  }  }
103    
104    
105    /* Load the GPG environment. On the first start, some
106       checks are performed to find out in what state GPG is.
107       Return value: 0  everything OK.
108                     >0  fatal error.
109                     -1 public keyring is empty or does not exist. */
110    static int
111    load_gpg_env (void)
112    {
113        SECURITY_ATTRIBUTES sec_attr;
114        char *p;
115        char *pkr;
116    
117        p = get_reg_entry_gpg4win ("gpg.exe");
118        if (!p)
119            return (1);
120        if (file_exist_check (p)) {
121            free_if_alloc (p);
122            return (1);
123        }
124        free_if_alloc (p);
125        p = multi_gnupg_path (0);
126        if (p && dir_exist_check (p)) {
127            memset (&sec_attr, 0, sizeof (sec_attr));
128            sec_attr.nLength = sizeof (sec_attr);
129            if (!CreateDirectory (p, &sec_attr)) {
130                msg_box (NULL, _("Could not create GPG home directory"),
131                         _("WinPT Error"), MB_ERR);
132                free_if_alloc (p);
133                return (2);
134            }
135        }
136        pkr = make_filename (p, "pubring", "gpg");
137        free_if_alloc (p);
138        if (!pkr)
139            return -1;
140        if (get_file_size (pkr) == 0) {
141            free_if_alloc (pkr);
142            return -1;
143        }
144        return 0;
145    }
146    
147    
148  /* check if the default key from the gpg.conf file is available in the  /* check if the default key from the gpg.conf file is available in the
149     keyring. if not, bail out because encryption won't work properly then. */     keyring. if not, bail out because encryption won't work properly then. */
150  static int  static int
# Line 121  check_default_key (gpg_keycache_t kc) Line 152  check_default_key (gpg_keycache_t kc)
152  {  {
153      gpgme_key_t key;      gpgme_key_t key;
154      gpgme_error_t err = GPG_ERR_NO_ERROR;      gpgme_error_t err = GPG_ERR_NO_ERROR;
155      char * defkey;      char *defkey;
156    
157      defkey = get_gnupg_default_key ();      defkey = get_gnupg_default_key ();
158      if (defkey)      if (defkey)
159          err = gpg_keycache_find_key (kc, defkey, 0, &key);          err = gpg_keycache_find_key (kc, defkey, 0, &key);
160      else      else
161          msg_box (NULL, _("No useable secret key found."), _("WinPT Error"), MB_ERR);          msg_box (NULL, _("No useable secret key found."),
162                     _("WinPT Error"), MB_ERR);
163      free_if_alloc (defkey);      free_if_alloc (defkey);
164      return err? -1 : 0;      return err? -1 : 0;
165  }  }
166    
167    
168  /* Return the WinPT program file name (with full pathname). */  /* Return the WinPT program file name (with full pathname). */
169  static const char *  static const char*
170  get_prog_part (const char * fname, int use_cwd)  get_prog_part (const char * fname, int use_cwd)
171  {  {
172      static char program[512];      static char program[512];
# Line 168  get_prog_part (const char * fname, int u Line 200  get_prog_part (const char * fname, int u
200    
201  /* Check that the underlying crypto engine fullfills the minimal  /* Check that the underlying crypto engine fullfills the minimal
202     requirements so all commands work properly. */     requirements so all commands work properly. */
203  static int  static bool
204  check_crypto_engine (void)  check_crypto_engine (void)
205  {  {
206      int ma=1, mi=4, pa=2; /* GPG 1.4.2 */      int ma=0, mi=0, pa=0;
207      int rc;      int rc;
208    
209      rc = check_gnupg_engine (&ma, &mi, &pa);      rc = check_gnupg_engine (NEED_GPG_VERSION, &ma, &mi, &pa);
210      if (rc == -1) {      if (rc == -1) {
211          msg_box (NULL, _("Could not read GnuPG version."),          msg_box (NULL, _("Could not read GnuPG version."),
212                   _("WinPT Error"), MB_ERR);                   _("WinPT Error"), MB_ERR);
213          return rc;          return false;
214      }      }
215      else if (rc) {      else if (rc) {
216          log_box (_("WinPT Error"), MB_ERR,          log_box (_("WinPT Error"), MB_ERR,
217                   _("Sorry, you need a newer GPG version.\n"                   _("Sorry, you need a newer GPG version.\n"
218                     "GPG version %d.%d.%d required GPG version "MIN_GPG_VER),                     "GPG version %d.%d.%d required GPG version "NEED_GPG_VERSION),
219                     ma, mi, pa);                     ma, mi, pa);
220          return rc;          return false;
221      }      }
222      /* We enable smartcard support for GPG: >= 2 or >= 1.4.3 */      /* We enable smartcard support for GPG: >= 2 or >= 1.4.3 */
223      if (ma > 1 || pa >= 3)      if (ma > 1 || pa >= 3)    
224          scard_support = 1;          scard_support = 1;
225    
226      gpgver[0] = ma;      gpgver[0] = ma;
227      gpgver[1] = mi;      gpgver[1] = mi;
228      gpgver[2] = pa;      gpgver[2] = pa;
229      return rc;      return true;
230  }  }
231    
232    
# Line 203  check_crypto_engine (void) Line 235  check_crypto_engine (void)
235  static int  static int
236  load_keyserver_conf (int quiet)  load_keyserver_conf (int quiet)
237  {  {
238      const char * t;      char *buf;
239        const char *t;
240      int rc;      int rc;
241    
242      if (reg_prefs.kserv_conf)      /* Create $APPDATA\winpt if needed. */
243          t = reg_prefs.kserv_conf;      buf = make_special_filename (CSIDL_APPDATA, "winpt", NULL);
244      else if (!file_exist_check (get_prog_part ("keyserver.conf", 0)))      if (buf && dir_exist_check (buf) && !CreateDirectory (buf, NULL)) {
245            MessageBox (NULL, _("Failed to create WinPT directory"),
246                        _("Keyserver"), MB_ERR);
247            free_if_alloc (buf);
248            return -1;
249        }
250        free_if_alloc (buf);
251    
252        /* Check for $APPDATA\winpt\keyserver.conf */
253        buf = make_special_filename (CSIDL_APPDATA, "winpt\\keyserver.conf", NULL);
254    
255        if (!file_exist_check (get_prog_part ("keyserver.conf", 0)))
256          t = get_prog_part ("keyserver.conf", 0);          t = get_prog_part ("keyserver.conf", 0);
257      else      else
258          t = "keyserver.conf";          t = "keyserver.conf";
259        if (file_exist_check (t) == 0 && file_exist_check (buf) != 0) {
260            //log_box (_("Keyserver"), MB_INFO,
261            //       _("keyserver.conf will be copied to \"%s\"\r\n"), buf);
262            if (!CopyFile (t, buf, FALSE)) {
263                MessageBox (NULL, _("Failed to copy the keyserver.conf"),
264                            _("Keyserver"), MB_ERR);
265                free_if_alloc (buf);
266                return -1;
267            }
268            t = buf;
269        }
270        else
271            t = buf;
272        
273      rc = kserver_load_conf (t);      rc = kserver_load_conf (t);
274      if (rc && !quiet)      if (rc && !quiet)
275          msg_box (NULL, winpt_strerror (rc), _("Keyserver"), MB_ERR);          msg_box (NULL, winpt_strerror (rc), _("Keyserver"), MB_ERR);
276        else {
277            free_if_alloc (reg_prefs.kserv_conf);
278            reg_prefs.kserv_conf = m_strdup (t);
279        }
280        free_if_alloc (buf);
281      return rc;      return rc;
282  }  }
283    
284    
285    /* Check if both keyrings are empty. This indicates that
286       WinPT should offer to generate a key pair. */
287    static bool
288    check_for_empty_keyrings (bool pub_only)
289    {
290        char *p;
291        int n = 0;
292    
293        p = get_gnupg_keyring (1, 0);
294        if (file_exist_check (p) == 0 && get_file_size (p) == 0)
295            n++;
296        free_if_alloc (p);
297        if (pub_only)
298            return n == 1? true : false;
299        p = get_gnupg_keyring (0, 0);
300        if (file_exist_check (p) == 0 && get_file_size (p) == 0)
301            n++;
302        free_if_alloc (p);
303        return n==2? true : false;
304    }
305    
306    
307  /* Enable the mobility mode. */  /* Enable the mobility mode. */
308  static void  static void
309  enable_mobile_mode (void)  enable_mobile_mode (void)
# Line 236  enable_mobile_mode (void) Line 321  enable_mobile_mode (void)
321      reg_prefs.use_viewer = 0; /* XXX */      reg_prefs.use_viewer = 0; /* XXX */
322  }  }
323    
 char* multi_gnupg_path (void);  
   
 const char * fm_get_file_type (const char *fname, int *r_type);  
324    
325  /* Main entry point. */  /* Main entry point. */
326  int WINAPI  int WINAPI
# Line 246  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 328  WinMain (HINSTANCE hinst, HINSTANCE hpre
328  {  {
329      WNDCLASS wc = {0, winpt_main_proc, 0, 0, hinst, 0, 0, 0, 0, PGM_NAME};      WNDCLASS wc = {0, winpt_main_proc, 0, 0, hinst, 0, 0, 0, 0, PGM_NAME};
330      HACCEL accel_tab;      HACCEL accel_tab;
331      int rc, ec, created = 0, nfiles = 0;      MSG msg;
332        HWND hwnd = NULL;
333        WORD ver[3], ptdver[4];
334        int rc, ec, created = 0;
335      int first_start = 0, start_gpgprefs = 0;      int first_start = 0, start_gpgprefs = 0;
336      int winpt_inst_found = 0;      int winpt_inst_found = 0;
337        int start_manager = 0;
338      const char *s;      const char *s;
     MSG msg;  
     HWND hwnd = NULL;  
339    
340      glob_hinst = hinst;      glob_hinst = hinst;
   
341      if (cmdline && stristr (cmdline, "--stop")) {      if (cmdline && stristr (cmdline, "--stop")) {
342          hwnd = FindWindow ("WinPT", "WinPT");          hwnd = FindWindow ("WinPT", "WinPT");
343          if (hwnd != NULL)          if (hwnd != NULL)
344              PostMessage (hwnd, WM_DESTROY, 0, 0);              PostMessage (hwnd, WM_DESTROY, 0, 0);
345          return 0;          return 0;
346      }      }
347        
348  #ifdef _DEBUG      /*
349        OSVERSIONINFO osinf;
350        memset (&osinf, 0, sizeof (osinf));
351        if (GetVersionEx (&osinf) &&
352            osinf.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
353            osinf.dwMinorVersion == 0) {
354            msg_box (NULL, "WinPT propably does not work on Windows 95 without restrictions",
355                     "WinPT Warning", MB_INFO);
356        }
357        */
358    
359        #ifdef _DEBUG
360      gpg_set_debug_mode (1);      gpg_set_debug_mode (1);
361      debug = 1;      debug = 1;
362  #endif      #endif
363    
364        get_file_version ("WinPT.exe", &ver[0], &ver[1], &ver[2], &ver[3]);
365        get_file_version ("PTD.dll", &ptdver[0], &ptdver[1],
366                                     &ptdver[2], &ptdver[3]);
367        /* XXX
368        if (ptdver[0] != ver[0] || ptdver[1] != ver[1]|| ptdver[2] != ver[2]) {
369            log_box (_("WinPT Error"), MB_ERR,
370                     _("The PTD.dll file has a different version than WinPT.exe\n"
371                       "Please update the PTD.dll to version %d.%d.%d"),
372                       ver[0], ver[1], ver[2]);
373            return 0;
374        }
375        */
376    
377      if (gpg_md_selftest ()) {      if (gpg_md_selftest ()) {
378          msg_box (NULL, _("Cryptographic selftest failed."),          msg_box (NULL, _("Cryptographic selftest failed."),
# Line 273  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 380  WinMain (HINSTANCE hinst, HINSTANCE hpre
380          return 0;          return 0;
381      }      }
382    
383      s = gpgme_check_version (MIN_GPGME_VER);      s = gpgme_check_version (NEED_GPGME_VERSION);
384      if (!s || !*s) {      if (!s || !*s) {
385          msg_box (NULL, _("A newer GPGME version is needed; at least "MIN_GPGME_VER),          msg_box (NULL, _("A newer GPGME version is needed; at least "NEED_GPGME_VERSION),
386                   _("WinPT Error"), MB_ERR);                   _("WinPT Error"), MB_ERR);
387          return 0;          return 0;
388      }      }
# Line 291  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 398  WinMain (HINSTANCE hinst, HINSTANCE hpre
398      }      }
399    
400      set_default_kserver ();      set_default_kserver ();
401        load_gettext (winpt_inst_found);
402    
403      if (!mobile) {      if (!mobile) {
404          regist_inst_gnupg (1);          regist_inst_gnupg (1);
# Line 312  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 420  WinMain (HINSTANCE hinst, HINSTANCE hpre
420          gnupg_load_config ();          gnupg_load_config ();
421      }      }
422    
423        if (is_gpg4win_installed ())
424            load_gpg_env (); /* XXX: check return code. */
425    
426      rc = gnupg_check_homedir ();      rc = gnupg_check_homedir ();
427      if (rc) {      if (rc) {
428          log_box (_("WinPT Error"), MB_ERR,          log_box (_("WinPT Error"), MB_ERR,
# Line 319  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 430  WinMain (HINSTANCE hinst, HINSTANCE hpre
430                     "Please check the GPG registry settings:\n%s."),                     "Please check the GPG registry settings:\n%s."),
431                   winpt_strerror (rc));                   winpt_strerror (rc));
432          s = get_fileopen_dlg (GetActiveWindow (),          s = get_fileopen_dlg (GetActiveWindow (),
433                                _("Select GPG Public Keyring"),                                _("Select GPG Public Keyring"),
434                                _("GPG Keyrings (*.gpg)\0*.gpg\0\0"),                                _("GPG Keyrings (*.gpg)\0*.gpg\0\0"),
435                                NULL);                                NULL);
436          if (s != NULL) {          if (s != NULL) {
437              size_t n;              size_t n;
438              char * p = strrchr (s, '\\');              char *p = strrchr (s, '\\');
439              if (!p)              if (!p)
440                  BUG (0);                  BUG (0);
441              n = p - s;              n = p - s;
442              if (n) {              if (n) {
443                  char * file = new char[n+1];                  char *file = new char[n+1];
444                  if (!file)                  if (!file)
445                      BUG (NULL);                      BUG (NULL);
446                  memset (file, 0, n);                  memset (file, 0, n);
# Line 354  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 465  WinMain (HINSTANCE hinst, HINSTANCE hpre
465                               "correct  this problem?"), _("WinPT Error"),                               "correct  this problem?"), _("WinPT Error"),
466                               MB_INFO|MB_YESNO) == IDYES)                               MB_INFO|MB_YESNO) == IDYES)
467              start_gpgprefs = 1;              start_gpgprefs = 1;
468          else          else {
         {  
469              msg_box (NULL, winpt_strerror (rc), _("WinPT Error"), MB_ERR);              msg_box (NULL, winpt_strerror (rc), _("WinPT Error"), MB_ERR);
470              return 0;              return 0;
471          }          }
# Line 377  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 487  WinMain (HINSTANCE hinst, HINSTANCE hpre
487              return 0;              return 0;
488          }          }
489      }      }
490        if (check_for_empty_keyrings (false))
491            first_start = 1;
492    
493      if (!first_start) {      if (!first_start) {
494          rc = gpg_check_permissions (1);          rc = gpg_check_permissions (1);
# Line 385  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 497  WinMain (HINSTANCE hinst, HINSTANCE hpre
497          else if (rc)          else if (rc)
498              return 0;              return 0;
499      }      }
500        
     load_gettext (winpt_inst_found);  
501      init_gnupg_table ();      init_gnupg_table ();
502    
503      nfiles = fm_parse_command_line (cmdline);      if (fm_parse_command_line (cmdline) > 0) {
     if (nfiles > 0) {  
504          free_gnupg_table ();          free_gnupg_table ();
505          return 0;          return 0;
506      }      }
# Line 411  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 521  WinMain (HINSTANCE hinst, HINSTANCE hpre
521             to open the key manager. Otherwise start a new instance.             to open the key manager. Otherwise start a new instance.
522           */           */
523          HWND tray = FindWindow ("WinPT", "WinPT");          HWND tray = FindWindow ("WinPT", "WinPT");
524            if (stristr (cmdline, "keymanager"))
525                start_manager = ID_WINPT_KEY;
526            else
527                start_manager = ID_WINPT_CARD;
528          if (tray != NULL) {          if (tray != NULL) {
529              PostMessage (tray, WM_COMMAND, ID_WINPT_KEY, 0);              PostMessage (tray, WM_COMMAND, start_manager, 0);
530              free_gnupg_table ();              free_gnupg_table ();
531              return 0;              return 0;
532          }          }
         update_keycache (GetDesktopWindow ());  
         if (stristr (cmdline, "keymanager"))  
             dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_KEYMISC,  
                             GetDesktopWindow(), keymanager_dlg_proc, 0,  
                             _("Key Manager"), IDS_WINPT_KEYMISC);    
         else {  
             gpg_card_t crd = gpg_card_load ();  
             if (crd)  
                 dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_CARD_EDIT,  
                                   GetDesktopWindow(), card_edit_dlg_proc,  
                                   (LPARAM)crd, _("Card Manager"),  
                                   IDS_WINPT_CARD_EDIT);  
             gpg_card_release (crd);  
         }  
         /*  
         keycache_release (0);  
         free_gnupg_table ();  
         return 0;  
         */  
533      }      }
534    
535      /* If we found another WinPT instance, just quit to avoid it      /* If we found another WinPT instance, just quit to avoid it
# Line 446  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 541  WinMain (HINSTANCE hinst, HINSTANCE hpre
541      }      }
542    
543      if (cmdline) {      if (cmdline) {
544          if (stristr (cmdline, "--enable-debug") || stristr (cmdline, "--debug")) {          if (stristr (cmdline, "--enable-debug") ||
545                stristr (cmdline, "--debug")) {
546              gpg_set_debug_mode (1);              gpg_set_debug_mode (1);
547              winpt_debug_msg ();              winpt_debug_msg ();
548              debug = 1;              debug = 1;
# Line 479  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 575  WinMain (HINSTANCE hinst, HINSTANCE hpre
575    
576      if (!first_start && !start_gpgprefs) {      if (!first_start && !start_gpgprefs) {
577          gnupg_backup_options ();                  gnupg_backup_options ();        
578          rc = check_crypto_engine ();          if (!check_crypto_engine ()) {
         if (rc) {  
579              DestroyWindow (hwnd);              DestroyWindow (hwnd);
580              free_gnupg_table ();              free_gnupg_table ();
581              return 0;              return 0;
# Line 488  WinMain (HINSTANCE hinst, HINSTANCE hpre Line 583  WinMain (HINSTANCE hinst, HINSTANCE hpre
583      }      }
584            
585      if (start_gpgprefs) {      if (start_gpgprefs) {
         char *ring;  
   
586          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_GPGPREFS, hwnd,          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_GPGPREFS, hwnd,
587                          gpgprefs_dlg_proc, 0);                          gpgprefs_dlg_proc, 0);
588          ring = get_gnupg_keyring (0, !NO_STRICT);          if (check_for_empty_keyrings (true))
589          if (gnupg_access_keyring (0) == -1 && get_file_size (ring) == 0)              first_start = 1; /* The public keyring is empty! */
             first_start = 1; /* The keyring is empty! */  
         free_if_alloc (ring);  
590      }      }
591    
592      if (first_start) {      if (first_start) {
# Line 526  start: Line 617  start:
617              }              }
618              break;              break;
619    
620          case -1:          case -1: /* Cancel/Abort. */
621              DestroyWindow (hwnd);              DestroyWindow (hwnd);
622              free_gnupg_table ();              free_gnupg_table ();
623              return 0;              return 0;
# Line 558  start: Line 649  start:
649              }              }
650          }          }
651          if (check_default_key (c)) {          if (check_default_key (c)) {
652              char * p = get_gnupg_default_key ();              char *p = get_gnupg_default_key ();
653              log_box (_("WinPT Error"), MB_ERR,              log_box (_("WinPT Error"), MB_ERR,
654                       _("Default key from the GPG options file could not be found.\n"                       _("Default key from the GPG options file could not be found.\n"
655                         "Please check your gpg.conf (options) to correct this:\n\n"                         "Please check your gpg.conf (options) to correct this:\n\n"
# Line 573  start: Line 664  start:
664                              elgamal_warn_dlg_proc, 0);                              elgamal_warn_dlg_proc, 0);
665      }      }
666    
667        if (start_manager)
668            PostMessage (hwnd, WM_COMMAND, start_manager, 0);
669    
670      accel_tab = LoadAccelerators (glob_hinst, (LPCTSTR)IDR_WINPT_ACCELERATOR);      accel_tab = LoadAccelerators (glob_hinst, (LPCTSTR)IDR_WINPT_ACCELERATOR);
671      keyring_check_last_access (); /* init */      keyring_check_last_access (); /* init */
672      while (GetMessage (&msg, hwnd, 0, 0)) {      while (GetMessage (&msg, hwnd, 0, 0)) {

Legend:
Removed from v.102  
changed lines
  Added in v.159

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26