Removed even more C++ style comments.
[obnox/wireshark/wip.git] / packaging / u3 / win32 / u3util.c
1 /* u3util.c
2  * Utility routines for U3 device support
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 /* Adapted from Microsoft Knowledge Base Article 178893
26  *
27  * http://support.microsoft.com/?kbid=178893
28  *
29  * and the U3 Answer 106
30  *
31  * https://u3.custhelp.com/cgi-bin/u3/php/enduser/std_adp.php?p_faqid=106
32  *
33  * Indentation logic: 2-space
34  */
35
36 #include <windows.h>
37 #include <winreg.h>
38 #include <shlobj.h>
39
40
41 #define WIRESHARK_ASSOC "u3-wireshark-file"
42 #define WIRESHARK_DESC  "U3 Wireshark File"
43
44 #define SHELL                "\\Shell"
45 #define SHELL_OPEN           "\\Shell\\open"
46 #define SHELL_OPEN_COMMAND   "\\Shell\\open\\command"
47 #define DEFAULT_ICON         "\\DefaultIcon"
48
49 #define WINPCAP_PACKAGE      "\\WinPcap_4_0_2.exe"
50 #define WINPCAP_KEY          "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\WinPcapInst"
51 #define WINPCAP_UNINSTALL    "UninstallString"
52 #define WINPCAP_U3INSTALLED  "U3Installed"  /* indicate the U3 device that installed WinPcap */
53
54 #define MY_CAPTURES          "\\My Captures"
55
56 #define BUFSIZ              256
57 #define FILEBUFSIZ          4096
58
59 #define ENV_FILENAME        "\\u3_environment.txt"
60 #define U3UTIL_APPSTART     "\\u3util.exe appStart %1"
61 #define WIRESHARK_EXE       "\\wireshark.exe"
62
63 static char *extensions[] = {
64   ".5vw",
65   ".acp",
66   ".apc",
67   ".atc",
68   ".bfr",
69   ".cap",
70   ".enc",
71   ".erf",
72   ".fdc",
73   ".pcap",
74   ".pkt",
75   ".tpc",
76   ".tr1",
77   ".trace",
78   ".trc",
79   ".wpc",
80   ".wpz",
81   /* and BER encoded files */
82   ".cer",
83   ".crt",
84   ".crl",
85   ".p12",
86   ".pfx",
87   ".asn",
88   ".spf",
89   ".p7c",
90   ".p7s",
91   ".p7m",
92   NULL
93 };
94
95 static char *environmentvars[] = {
96   "U3_DEVICE_SERIAL",
97   "U3_DEVICE_PATH",
98   "U3_DEVICE_DOCUMENT_PATH",
99   "U3_DEVICE_VENDOR",
100   "U3_DEVICE_PRODUCT",
101   "U3_DEVICE_VENDOR_ID",
102   "U3_APP_DATA_PATH",
103   "U3_HOST_EXEC_PATH",
104   "U3_DEVICE_EXEC_PATH",
105   "U3_ENV_VERSION",
106   "U3_ENV_LANGUAGE",
107   NULL,
108 };
109
110 #define TA_FAILED 0
111 #define TA_SUCCESS_CLEAN 1
112 #define TA_SUCCESS_KILL 2
113 #define TA_SUCCESS_16 3
114
115 DWORD TerminateApp( DWORD dwPID, DWORD dwTimeout ) ;
116 DWORD Terminate16App( DWORD dwPID, DWORD dwThread, WORD w16Task, DWORD dwTimeout );
117
118 #include <vdmdbg.h>
119
120 typedef struct
121 {
122   DWORD   dwID ;
123   DWORD   dwThread ;
124 } TERMINFO ;
125
126 /* Declare Callback Enum Functions. */
127 BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;
128 BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam ) ;
129
130 /*----------------------------------------------------------------
131   DWORD TerminateApp( DWORD dwPID, DWORD dwTimeout )
132
133   Purpose:
134       Shut down a 32-Bit Process (or 16-bit process under Windows 95)
135
136   Parameters:
137       dwPID
138          Process ID of the process to shut down.
139
140       dwTimeout
141          Wait time in milliseconds before shutting down the process.
142
143    Return Value:
144       TA_FAILED - If the shutdown failed.
145       TA_SUCCESS_CLEAN - If the process was shutdown using WM_CLOSE.
146       TA_SUCCESS_KILL - if the process was shut down with
147          TerminateProcess().
148       NOTE:  See header for these defines.
149    ----------------------------------------------------------------*/
150
151 DWORD TerminateApp( DWORD dwPID, DWORD dwTimeout )
152 {
153   HANDLE   hProc ;
154   DWORD   dwRet ;
155
156   /* If we can't open the process with PROCESS_TERMINATE rights,
157    * then we give up immediately. */
158   hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID);
159
160   if(hProc == NULL){
161     return TA_FAILED;
162   }
163
164   if(dwTimeout) {
165     /* we are prepared to wait */
166
167     /* TerminateAppEnum() posts WM_CLOSE to all windows whose PID */
168     /* matches your process's. */
169     EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;
170
171     /* Wait on the handle. If it signals, great. If it times out, */
172     /* then you kill it. */
173     if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)
174       dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
175     else
176       dwRet = TA_SUCCESS_CLEAN ;
177   } else {
178     /* we immediately kill the proces */
179     dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
180   }
181
182   CloseHandle(hProc) ;
183
184   return dwRet ;
185 }
186
187 /*----------------------------------------------------------------
188   DWORD Terminate16App( DWORD dwPID, DWORD dwThread,
189                         WORD w16Task, DWORD dwTimeout )
190
191    Purpose:
192       Shut down a Win16 APP.
193
194    Parameters:
195       dwPID
196          Process ID of the NTVDM in which the 16-bit application is
197          running.
198
199       dwThread
200          Thread ID of the thread of execution for the 16-bit
201          application.
202
203       w16Task
204          16-bit task handle for the application.
205
206       dwTimeout
207          Wait time in milliseconds before shutting down the task.
208
209    Return Value:
210       If successful, returns TA_SUCCESS_16
211       If unsuccessful, returns TA_FAILED.
212       NOTE:  These values are defined in the header for this
213       function.
214
215    NOTE:
216       You can get the Win16 task and thread ID through the
217       VDMEnumTaskWOW() or the VDMEnumTaskWOWEx() functions.
218    ----------------------------------------------------------------*/
219
220 DWORD Terminate16App( DWORD dwPID, DWORD dwThread, WORD w16Task, DWORD dwTimeout )
221 {
222   HINSTANCE      hInstLib ;
223   TERMINFO      info ;
224
225   /* You will be calling the functions through explicit linking */
226   /* so that this code will be binary compatible across */
227   /* Win32 platforms. */
228   BOOL (WINAPI *lpfVDMTerminateTaskWOW)(DWORD dwProcessId, WORD htask) ;
229
230   hInstLib = LoadLibraryA( "VDMDBG.DLL" ) ;
231   if( hInstLib == NULL )
232     return TA_FAILED ;
233
234   /* Get procedure addresses. */
235   lpfVDMTerminateTaskWOW = (BOOL (WINAPI *)(DWORD, WORD ))
236     GetProcAddress( hInstLib, "VDMTerminateTaskWOW" ) ;
237
238   if( lpfVDMTerminateTaskWOW == NULL )
239     {
240       FreeLibrary( hInstLib ) ;
241       return TA_FAILED ;
242     }
243
244   /* Post a WM_CLOSE to all windows that match the ID and the */
245   /* thread. */
246   info.dwID = dwPID ;
247   info.dwThread = dwThread ;
248   EnumWindows((WNDENUMPROC)Terminate16AppEnum, (LPARAM) &info) ;
249
250   /* Wait. */
251   Sleep( dwTimeout ) ;
252
253   /* Then terminate. */
254   lpfVDMTerminateTaskWOW(dwPID, w16Task) ;
255
256   FreeLibrary( hInstLib ) ;
257   return TA_SUCCESS_16 ;
258 }
259
260 BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
261 {
262   DWORD dwID ;
263
264   GetWindowThreadProcessId(hwnd, &dwID) ;
265
266   if(dwID == (DWORD)lParam)
267     {
268       PostMessage(hwnd, WM_CLOSE, 0, 0) ;
269     }
270
271   return TRUE ;
272 }
273
274 BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam )
275 {
276   DWORD      dwID ;
277   DWORD      dwThread ;
278   TERMINFO   *termInfo ;
279
280   termInfo = (TERMINFO *)lParam ;
281
282   dwThread = GetWindowThreadProcessId(hwnd, &dwID) ;
283
284   if(dwID == termInfo->dwID && termInfo->dwThread == dwThread )
285     {
286       PostMessage(hwnd, WM_CLOSE, 0, 0) ;
287     }
288
289   return TRUE ;
290 }
291
292
293 void ExecuteAndWait(char *buffer)
294 {
295   STARTUPINFO         si;
296   PROCESS_INFORMATION pi;
297
298   ZeroMemory(&si, sizeof(si));
299   si.cb = sizeof(si);
300   ZeroMemory(&pi, sizeof(pi));
301
302   if(CreateProcess(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
303     /* wait for the uninstall to finish */
304     (void) WaitForSingleObject(pi.hProcess, INFINITE);
305
306     (void)CloseHandle(pi.hProcess);
307     (void)CloseHandle(pi.hThread);
308
309   }
310 }
311
312 void app_start(int argc, char *argv[])
313 {
314   char *u3hostexecpath;
315   char *envvar;
316   char *end;
317   char buffer[BUFSIZ+1];
318   char inBuffer[FILEBUFSIZ+1];
319   HANDLE *file;
320   DWORD numRead = 0;
321   int i;
322
323   /* read any environment variables that may be set as we are probably running this from a file association */
324
325   buffer[0] = '\0';
326   strncat(buffer, argv[0], strlen(argv[0]) + 1);
327
328   /* truncate at last \\ */
329   if(end = strrchr(buffer, '\\'))
330     *end = '\0';
331
332   strncat(buffer, ENV_FILENAME, strlen(ENV_FILENAME) + 1);
333
334   /* open the file */
335   if((file = CreateFile(buffer, FILE_READ_DATA, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) {
336
337     /* read the whole file in in one go */
338     if(ReadFile(file, &inBuffer, FILEBUFSIZ, &numRead, NULL) != 0) {
339       /* we were successful - parse the lines */
340       inBuffer[numRead] = '\0'; /* null terminate the data */
341
342       envvar = inBuffer;
343
344       while(end = strchr(envvar, '\n')) {
345         /* we have a line */
346         *end++ = '\0';
347
348         _putenv(envvar);
349
350         /* point the next envar to the end */
351         envvar = end;
352       }
353     }
354
355     /* close the file */
356     CloseHandle(file);
357
358   }
359
360   /* exec wireshark */
361   if((u3hostexecpath = getenv("U3_HOST_EXEC_PATH")) != NULL) {
362
363     buffer[0] = '\0';
364     strncat(buffer, u3hostexecpath, strlen(u3hostexecpath) + 1);
365     strncat(buffer, WIRESHARK_EXE, strlen(WIRESHARK_EXE) + 1);
366
367     /* copy the remaining arguments across */
368     for(i = 2; i < argc; i++) {
369       strncat(buffer, " ", 2);
370       strncat(buffer, argv[i], strlen(argv[i]) + 1);
371     }
372
373     ExecuteAndWait(buffer);
374
375   }
376
377 }
378
379
380 void app_stop(DWORD timeOut)
381 {
382   DWORD  pid = 0;
383   HANDLE hFind = INVALID_HANDLE_VALUE;
384   WIN32_FIND_DATA find_file_data;
385   DWORD dwError;
386   char *u3_host_exec_path;
387   char dir_spec[MAX_PATH+1];
388   char file_name[MAX_PATH+1];
389
390   u3_host_exec_path = getenv("U3_HOST_EXEC_PATH");
391
392   strncpy(dir_spec, u3_host_exec_path, strlen(u3_host_exec_path) + 1);
393   strncat(dir_spec, "\\*.pid", 7);
394
395   hFind = FindFirstFile(dir_spec, &find_file_data);
396
397   if(hFind != INVALID_HANDLE_VALUE) {
398
399     do {
400
401       pid = (DWORD)atoi(find_file_data.cFileName);
402
403       if(pid)
404         TerminateApp(pid, timeOut);
405
406       strncpy(file_name, u3_host_exec_path, strlen(u3_host_exec_path) + 1);
407       strncat(file_name, "\\", 2);
408       strncat(file_name, find_file_data.cFileName, strlen(find_file_data.cFileName) + 1);
409
410       DeleteFile(TEXT(file_name));
411
412     } while(FindNextFile(hFind, &find_file_data) != 0);
413
414     FindClose(hFind);
415
416   }
417
418 }
419
420 /* associate
421
422 Associate an filetype (extension) with the U3 Wireshark if it doesn't already have an association
423
424 */
425
426 void associate(char *extension)
427 {
428   HKEY key;
429   DWORD disposition;
430   char buffer[BUFSIZ];
431   int  buflen = BUFSIZ;
432
433   buffer[0] = '\0';
434
435   /* open the HKCR  extension  key*/
436   if(RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, (KEY_READ | KEY_WRITE), NULL, &key, &disposition) == ERROR_SUCCESS) {
437
438     /* we could look at the disposition - but we don't bother */
439     if((RegQueryValueEx(key, "", NULL, NULL, buffer, &buflen) != ERROR_SUCCESS) || (buffer[0] == '\0')) {
440
441       (void)RegSetValueEx(key, "", 0, REG_SZ, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
442     }
443
444     RegCloseKey(key);
445   }
446
447 }
448
449 BOOL save_environment()
450 {
451   char **envptr;
452   char *envval;
453   HANDLE *file;
454   char buffer[BUFSIZ+1];
455   DWORD  buflen;
456   DWORD  numWritten;
457   BOOL   retval = FALSE;
458
459   envval = getenv("U3_HOST_EXEC_PATH");
460
461   buffer[0] = '\0';
462   strncat(buffer, envval, strlen(envval) + 1);
463   strncat(buffer, ENV_FILENAME, strlen(ENV_FILENAME) + 1);
464
465   /* open the file */
466   if((file = CreateFile(buffer, FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) {
467
468     for(envptr = environmentvars; *envptr; envptr++) {
469
470       if(envval = getenv(*envptr)) {
471         /* write it out */
472
473         buffer[0] = '\0';
474         strncat(buffer, *envptr, strlen(*envptr) + 1);
475         strncat(buffer, "=", 2);
476         strncat(buffer, envval, strlen(envval) + 1);
477         strncat(buffer, "\n", 2);
478
479         buflen = strlen(buffer);
480
481         WriteFile(file, buffer, buflen, &numWritten, NULL);
482       }
483
484     }
485
486     /* close the file */
487     CloseHandle(file);
488
489     retval = TRUE;
490
491   }
492
493   return retval;
494
495 }
496
497
498 /* disassociate
499
500 Remove any file types that are associated with the U3 Wireshark (which is being removed)
501
502 */
503
504
505 void disassociate(char *extension)
506 {
507   HKEY key;
508   DWORD disposition;
509   char buffer[BUFSIZ];
510   int  buflen = BUFSIZ;
511   boolean delete_key = FALSE;
512
513   buffer[0] = '\0';
514
515   /* open the HKCR  extension  key*/
516   if(RegOpenKeyEx(HKEY_CLASSES_ROOT, extension, 0, (KEY_READ | KEY_WRITE), &key) == ERROR_SUCCESS) {
517
518     if(RegQueryValueEx(key, "", NULL, NULL, buffer, &buflen) == ERROR_SUCCESS) {
519
520       if(!strncmp(buffer, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1))
521         delete_key = TRUE;
522     }
523
524     RegCloseKey(key);
525   }
526
527   if(delete_key)
528     RegDeleteKey(HKEY_CLASSES_ROOT, extension);
529 }
530
531 /* host_configure
532
533 Configure the host for the U3 Wireshark. This involves:
534 1) registering the U3 Wireshark with capture file types
535 2) installing WinPcap if not already installed
536 3) create a "My Captures" folder on the U3 device if it doesn't already exist
537 */
538
539 void host_configure(void)
540 {
541   char **pext;
542   HKEY  key;
543   DWORD disposition;
544   char *u3_host_exec_path;
545   char *u3_device_exec_path;
546   char *u3_device_serial;
547   char *u3_device_document_path;
548   char wireshark_path[MAX_PATH+1];
549   char winpcap_path[MAX_PATH+1];
550   char my_captures_path[MAX_PATH+1];
551   char reg_key[BUFSIZ];
552   char buffer[BUFSIZ];
553   int  buflen = BUFSIZ;
554   boolean hasWinPcap = FALSE;
555
556   /* CREATE THE U3 Wireshark TYPE */
557   if(RegCreateKeyEx(HKEY_CLASSES_ROOT, WIRESHARK_ASSOC, 0, NULL, 0,
558                     (KEY_READ | KEY_WRITE), NULL, &key, &disposition) == ERROR_SUCCESS) {
559
560     (void)RegSetValueEx(key, "", 0, REG_SZ, WIRESHARK_DESC, strlen(WIRESHARK_DESC) + 1);
561
562     RegCloseKey(key);
563   }
564
565   /* compute the U3 path to wireshark */
566   u3_host_exec_path = getenv("U3_HOST_EXEC_PATH");
567   strncpy(wireshark_path, u3_host_exec_path, strlen(u3_host_exec_path) + 1);
568   strncat(wireshark_path, U3UTIL_APPSTART, strlen(U3UTIL_APPSTART) + 1);
569
570   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
571   strncat(reg_key, SHELL_OPEN_COMMAND, strlen(SHELL_OPEN_COMMAND) + 1);
572
573   /* associate the application */
574   if(RegCreateKeyEx(HKEY_CLASSES_ROOT, reg_key, 0, NULL, 0,
575                     (KEY_READ | KEY_WRITE), NULL, &key, &disposition) == ERROR_SUCCESS) {
576
577     (void)RegSetValueEx(key, "", 0, REG_SZ, wireshark_path, strlen(wireshark_path) + 1);
578
579     RegCloseKey(key);
580   }
581
582   /* associate the icon */
583   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
584   strncat(reg_key, DEFAULT_ICON, strlen(DEFAULT_ICON) + 1);
585
586   /* the icon is in the exe */
587   strncpy(wireshark_path, u3_host_exec_path, strlen(u3_host_exec_path) + 1);
588   strncat(wireshark_path, WIRESHARK_EXE, strlen(WIRESHARK_EXE) + 1);
589   strncat(wireshark_path, ",1", 3);
590
591   /* associate the application */
592   if(RegCreateKeyEx(HKEY_CLASSES_ROOT, reg_key, 0, NULL, 0,
593                     (KEY_READ | KEY_WRITE), NULL, &key, &disposition) == ERROR_SUCCESS) {
594
595     (void)RegSetValueEx(key, "", 0, REG_SZ, wireshark_path, strlen(wireshark_path) + 1);
596
597     RegCloseKey(key);
598   }
599
600   /* CREATE THE FILE ASSOCIATIONS */
601
602   for(pext = extensions; *pext; pext++)
603     associate(*pext);
604
605   /* update icons */
606   SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
607
608   /* START WINPCAP INSTALLATION IF NOT ALREADY INSTALLED */
609
610   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINPCAP_KEY, 0, (KEY_READ), &key) == ERROR_SUCCESS) {
611
612     if(RegQueryValueEx(key, WINPCAP_UNINSTALL, NULL, NULL, buffer, &buflen) == ERROR_SUCCESS) {
613
614       if(buffer[0] != '\0')
615         hasWinPcap = TRUE;
616     }
617
618     RegCloseKey(key);
619   }
620
621   if(!hasWinPcap &&
622      (MessageBox(NULL,
623                  TEXT("If you want to capture packets from the network you will need to install WinPcap.\nIt will be uninstalled when you remove your U3 device.\n\nDo you want to install WinPcap?"),
624                  TEXT("U3 Wireshark: Install WinPcap?"),
625                  MB_YESNO|MB_TOPMOST|MB_ICONQUESTION) == IDYES)) {
626
627     /* compute the U3 path to the WinPcap installation package - it stays on the device */
628     u3_device_exec_path = getenv("U3_DEVICE_EXEC_PATH");
629     strncpy(winpcap_path, "\"", 2);
630     strncat(winpcap_path, u3_device_exec_path, strlen(u3_device_exec_path) + 1);
631     strncat(winpcap_path, WINPCAP_PACKAGE, strlen(WINPCAP_PACKAGE) + 1);
632     strncat(winpcap_path, "\"", 2);
633
634     ExecuteAndWait(winpcap_path);
635
636     /* if installation was successful this key will now exist */
637     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINPCAP_KEY, 0, (KEY_READ | KEY_WRITE), &key) == ERROR_SUCCESS) {
638
639       u3_device_serial = getenv("U3_DEVICE_SERIAL");
640
641       (void)RegSetValueEx(key, WINPCAP_U3INSTALLED, 0, REG_SZ, u3_device_serial, strlen(u3_device_serial) + 1);
642
643     }
644   }
645
646   /* CREATE THE "My Captures" FOLDER IF IT DOESN'T ALREADY EXIST */
647
648   u3_device_document_path = getenv("U3_DEVICE_DOCUMENT_PATH");
649   strncpy(my_captures_path, u3_device_document_path, strlen(u3_device_document_path) + 1);
650   strncat(my_captures_path, MY_CAPTURES, strlen(MY_CAPTURES) + 1);
651
652   /* don't care if it succeeds or fails */
653   (void) CreateDirectory(my_captures_path, NULL);
654
655   /* Save the environment so we can use it in the file assocation */
656   save_environment();
657 }
658
659 /* host_cleanup
660
661 Remove any references to the U3 Wireshark from the host. This involves:
662 1) Removing the U3 Wireshark file type associations
663 2) Uninstalling WinPcap if we installed it.
664    If the user cancels the uninstallation of WinPcap, we will not try and remove it again.
665
666 */
667
668 void host_clean_up(void)
669 {
670   HKEY  key;
671   DWORD disposition;
672   char **pext;
673   char *u3_device_serial;
674   char buffer[BUFSIZ];
675   int buflen = BUFSIZ;
676   char reg_key[BUFSIZ];
677
678   /* the device has been removed -
679      just close the application as quickly as possible */
680
681   app_stop(0);
682
683   /* DELETE THE FILE ASSOCIATIONS */
684   for(pext = extensions; *pext; pext++)
685     disassociate(*pext);
686
687   /* update icons */
688   SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
689
690   /* DELETE THE U3 Wireshark TYPE */
691   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
692   strncat(reg_key, SHELL_OPEN_COMMAND, strlen(SHELL_OPEN_COMMAND) + 1);
693
694   RegDeleteKey(HKEY_CLASSES_ROOT, reg_key);
695
696   /* delete the open key */
697   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
698   strncat(reg_key, SHELL_OPEN, strlen(SHELL_OPEN) + 1);
699
700   RegDeleteKey(HKEY_CLASSES_ROOT, reg_key);
701
702   /* delete the shell key */
703   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
704   strncat(reg_key, SHELL, strlen(SHELL) + 1);
705
706   RegDeleteKey(HKEY_CLASSES_ROOT, reg_key);
707
708   /* delete the icon key */
709   strncpy(reg_key, WIRESHARK_ASSOC, strlen(WIRESHARK_ASSOC) + 1);
710   strncat(reg_key, DEFAULT_ICON, strlen(DEFAULT_ICON) + 1);
711
712   RegDeleteKey(HKEY_CLASSES_ROOT, reg_key);
713
714   /* finally delete the toplevel key */
715   RegDeleteKey(HKEY_CLASSES_ROOT, WIRESHARK_ASSOC);
716
717   /* UNINSTALL WINPCAP ONLY IF WE INSTALLED IT */
718   buffer[0] = '\0';
719
720   /* see if WinPcap is installed */
721   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINPCAP_KEY, 0, (KEY_READ | KEY_WRITE), &key) == ERROR_SUCCESS) {
722
723     /* see if a U3 device installed the package */
724     if(RegQueryValueEx(key, WINPCAP_U3INSTALLED, NULL, NULL, buffer, &buflen) == ERROR_SUCCESS) {
725
726       u3_device_serial = getenv("U3_DEVICE_SERIAL");
727
728       /* see if this U3 device installed the package */
729       if(!strncmp(buffer, u3_device_serial, strlen(u3_device_serial) + 1)) {
730
731         buffer[0] = '"';
732         buflen = BUFSIZ-1;
733         /* we installed WinPcap - we should now uninstall it - read the uninstall string */
734         (void) RegQueryValueEx(key, WINPCAP_UNINSTALL, NULL, NULL, &buffer[1], &buflen);
735         strncat(buffer, "\"", 2); /* close the quotes */
736
737         /* delete our value */
738         RegDeleteValue(key, WINPCAP_U3INSTALLED);
739
740       } else {
741         /* empty the buffer */
742         buffer[0] = '\0';
743       }
744     }
745
746     RegCloseKey(key);
747   }
748
749   if(*buffer) {
750     /* we have an uninstall string */
751     ExecuteAndWait(buffer);
752   }
753
754 }
755
756 main(int argc, char *argv[])
757 {
758   DWORD time_out = 0;
759   char *u3_is_device_available;
760
761   u3_is_device_available = getenv("U3_IS_DEVICE_AVAILABLE");
762
763   if(u3_is_device_available && !strncmp(u3_is_device_available, "true", 4))
764     /* the device is available - wait for user to respond to any dialogs */
765     time_out = INFINITE;
766
767   if(argc > 1) {
768
769     if(!strncmp(argv[1], "hostConfigure", 13))
770       host_configure();
771     else if(!strncmp(argv[1], "appStart", 9))
772       app_start(argc, argv);
773     else if(!strncmp(argv[1], "appStop", 8))
774       app_stop(time_out);
775     else if(!strncmp(argv[1], "hostCleanUp", 11))
776       host_clean_up();
777
778   }
779
780   exit(0);
781 }