2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * INCLUDES _________________________________________________________________
16 #include <afs/param.h>
18 #include <afs/fileutil.h>
31 #include <WINNT/afsreg.h>
32 #include <WINNT/afssw.h>
33 #include <WINNT/talocale.h>
36 #include "progress_dlg.h"
38 #include "forceremove.h"
42 * PROTOTYPES _________________________________________________________________
45 static char *GetAppInstallDir(struct APPINFO
*pApp
, BOOL bRemembered
);
46 BOOL
UninstallCredsTool();
47 BOOL
ServerSpecificUninstall();
48 BOOL
ClientSpecificUninstall();
53 * DEFINITIONS _________________________________________________________________
56 #define SUCALLCONV WINAPI
58 #define UNINSTALL_TEMP_INFO_KEY "HKEY_LOCAL_MACHINE\\Software\\AfsUninstallTempInfo"
59 #define INSTALL_DIR_VALUE_NAME "InstallDir"
61 #define AFS_PRESERVED_CFG_INFO_KEY "HKEY_LOCAL_MACHINE\\Software\\AfsPreservedConfigInfo"
63 #define MS_SHARED_FILES_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs"
65 // Log file to use when running in silent mode
66 #define UNINSTALL_ERROR_LOG_NAME "\\AfsUninstallErrorLog.txt"
67 #define INSTALL_ERROR_LOG_NAME "\\AfsInstallErrorLog.txt"
69 #define TARGETDIR "<TARGETDIR>"
70 #define WINDIR "<WINDIR>"
71 #define WINSYSDIR "<WINSYSDIR>"
73 #define WIN9X_START_MENU_REG_KEY "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
74 #define WIN9X_START_MENU_REG_VALUE "Programs"
76 #define WINNT_START_MENU_REG_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
77 #define WINNT_START_MENU_REG_VALUE "Common Programs"
79 #define LOCALE_ID_LEN 4
87 typedef BOOL (APP_UNINSTALL_FUNC
)();
98 char *pszSvcDisplayName
;
100 char *pszNetworkProviderOrder
;
102 // Message to use to tell the user that we have to stop the service
103 int nServiceShutdownMsgID
;
105 // Message to use for the progress dialog that is shown while
106 // waiting for the service to stop.
107 int nServiceShutdownProgressMsgID
;
109 // Location in registry of a key we can use to know that the app is installed
112 // Location in registry of this app's install dir
113 struct REGVALUE regInstallDir
;
116 char *pszLocalRoot
; // The root dir below the install dir
117 char *pszBinPath
; // Path to remove from the system path
119 // Generated files and directories to delete. These are both multistring lists.
120 char *pszDirsToDel
; // All files in these dirs will be deleted
121 char *pszFilesToDel
; // Use this if you want to delete files but leave the dir. Wildcards can be used.
123 // Registry values to remove
124 struct REGVALUE
*pRegValues
;
125 struct REGVALUE
*pWinNTRegValues
; // Only remove these if running WinNT
126 struct REGVALUE
*pWin9XRegValues
; // Only remove these if running Win9X
128 // Start menu entries to delete
129 char *pszStartMenuEntries
;
131 // Registry keys to save if a user wants to preserve config info during uninstall
132 char *pszRegKeysToPreserve
;
133 int nPreserveConfigInfoMsgID
;
135 // Uninstall func - used for things specific to this app
136 APP_UNINSTALL_FUNC
*pUninstallFunc
;
141 * App info structure for the Server product
143 struct APPINFO appServer
= {
149 AFSREG_SVR_SVC_DISPLAYNAME_DATA
,
151 0, // No network provider order
153 IDS_MUST_STOP_SERVER
,
154 IDS_WAITING_FOR_SERVER_TO_STOP
,
156 AFSREG_SVR_SW_VERSION_KEY
,
158 { AFSREG_SVR_SW_VERSION_KEY
, AFSREG_SVR_SW_VERSION_DIR_VALUE
},
164 TARGETDIR
"\\Server\\usr\\afs\\bin\\backup\0"
165 TARGETDIR
"\\Server\\usr\\afs\\bin\0"
166 TARGETDIR
"\\Server\\usr\\afs\\db\0"
167 TARGETDIR
"\\Server\\usr\\afs\\logs\0"
168 TARGETDIR
"\\Server\\usr\\afs\\etc\0"
169 TARGETDIR
"\\Server\\usr\\afs\\local\0"
170 TARGETDIR
"\\Server\\usr\\afs\0"
171 TARGETDIR
"\\Server\\usr\0",
174 TARGETDIR
"\\Common\\*.gid\0"
175 TARGETDIR
"\\Common\\*.fts\0",
178 0, // No NT only reg values
179 0, // No 9x only reg values
183 // Config info to preserve
184 AFSREG_SVR_SVC_KEY
"\0",
185 IDS_PRESERVE_SERVER_CONFIG_INFO
,
187 0 // No special uninstall function
190 // Registry values to remove for the Client
191 struct REGVALUE clientRegValues
[] = {
192 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", "{DC515C27-6CAC-11D1-BAE7-00C04FD140D2}" },
193 { 0, 0 } // This indicates there are no more entries
196 struct REGVALUE clientWinNTRegValues
[] = {
197 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\File Manager\\AddOns", "AFS Client FME" },
198 { "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", "SMBDeviceEnabled" },
202 struct REGVALUE clientWin9XRegValues
[] = {
203 { "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order", "TransarcAFSDaemon" },
208 * App info structure for the Client product
210 struct APPINFO appClient
= {
215 "5250435353004E657462696F730000",
216 AFSREG_CLT_SVC_DISPLAYNAME_DATA
,
220 IDS_MUST_STOP_CLIENT
,
221 IDS_WAITING_FOR_CLIENT_TO_STOP
,
223 AFSREG_CLT_SW_VERSION_KEY
,
225 { AFSREG_CLT_SW_VERSION_KEY
, AFSREG_CLT_SW_VERSION_DIR_VALUE
},
234 TARGETDIR
"\\Common\\*.gid\0"
235 TARGETDIR
"\\Common\\*.fts\0"
236 WINDIR
"\\..\\AFSCache\0"
237 WINDIR
"\\TEMP\\afsd.log\0"
238 TARGETDIR
"\\Client\\afsd.ini\0"
239 TARGETDIR
"\\Client\\afsdsbmt.ini\0"
240 TARGETDIR
"\\Client\\afsdcell.ini\0"
241 WINDIR
"\\TEMP\\afsd_init.log\0",
244 clientWinNTRegValues
,
245 clientWin9XRegValues
,
247 // Start menu entries to remove
250 // Config info to preserve
251 AFSREG_CLT_SVC_KEY
"\0",
252 IDS_PRESERVE_CLIENT_CONFIG_INFO
,
254 ClientSpecificUninstall
259 * App info structure for the Light Client product
261 struct APPINFO appLightClient
= {
272 // No service shutdown messages
276 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Light Client",
278 { AFSREG_CLT_SW_VERSION_KEY
, AFSREG_CLT_SW_VERSION_DIR_VALUE
},
287 TARGETDIR
"\\Common\\*.gid\0"
288 TARGETDIR
"\\Common\\*.fts\0",
291 clientWinNTRegValues
,
292 clientWin9XRegValues
,
294 // Start menu entries to remove
297 // Config info to preserve
298 AFSREG_CLT_SVC_KEY
"\0",
299 IDS_PRESERVE_LIGHT_CLIENT_CONFIG_INFO
,
306 * App info structure for the Control Center product
308 struct APPINFO appControlCenter
= {
309 "AFS Control Center",
317 // No network provider order
320 // No service shutdown messages
324 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center",
326 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center\\CurrentVersion", "PathName" },
335 TARGETDIR
"\\Common\\*.gid\0"
336 TARGETDIR
"\\Common\\*.fts\0",
339 0, // No NT only reg values
340 0, // No 9x only reg values
342 // Start menu entries to remove
345 // Config info to preserve
346 AFSREG_CLT_SVC_KEY
"\0",
347 IDS_PRESERVE_CC_CONFIG_INFO
,
349 0 // No uninstall function
354 * App info structure for the Sys Admin Doc files
356 struct APPINFO appDocs
= {
357 "AFS Supplemental Documentation",
365 // No network provider order
368 // No service shutdown messages
372 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation",
374 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation\\CurrentVersion", "PathName" },
383 TARGETDIR
"\\Common\\*.gid\0"
384 TARGETDIR
"\\Common\\*.fts\0",
387 0, // No NT only reg values
388 0, // No 9x only reg values
390 // Start menu entries to remove
391 "Documentation\\AFS for Windows Backup Command Reference.lnk\0Documentation\\AFS Command Reference Manual.lnk\0Documentation\\AFS System Administrator's Guide.lnk\0",
393 0, // No config info to preserve
395 0 // No uninstall function
399 // Shared and in-use files
412 struct FILEINFO fileInfo
[] = {
413 { TARGETDIR
"\\Common\\afsbosadmin.dll", SERVER
| CC
},
414 { TARGETDIR
"\\Common\\afscfgadmin.dll", SERVER
| CC
},
415 { TARGETDIR
"\\Common\\afsclientadmin.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
416 { TARGETDIR
"\\Common\\afskasadmin.dll", SERVER
| CC
},
417 { TARGETDIR
"\\Common\\afsptsadmin.dll", SERVER
| CC
},
418 { TARGETDIR
"\\Common\\afsvosadmin.dll", SERVER
| CC
},
419 { TARGETDIR
"\\Common\\afsadminutil.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
420 { TARGETDIR
"\\Common\\afsrpc.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
421 { TARGETDIR
"\\Common\\afsauthent.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
422 { TARGETDIR
"\\Common\\afspthread.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
423 { TARGETDIR
"\\Common\\TaAfsAppLib.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
424 { TARGETDIR
"\\Common\\afsprocmgmt.dll", SERVER
| CLIENT
| LCLIENT
},
425 { TARGETDIR
"\\Common\\afs_config.exe", CLIENT
| LCLIENT
| CC
},
426 { TARGETDIR
"\\Common\\afseventmsg_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
427 { TARGETDIR
"\\Common\\afslegal_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
428 { TARGETDIR
"\\Common\\afsserver_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
429 { TARGETDIR
"\\Common\\afssvrcfg_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
430 { TARGETDIR
"\\Common\\TaAfsAccountManager_????.dll",SERVER
| CLIENT
| LCLIENT
| CC
},
431 { TARGETDIR
"\\Common\\TaAfsAppLib_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
432 { TARGETDIR
"\\Common\\TaAfsServerManager_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
433 { TARGETDIR
"\\Common\\afscreds_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
434 { TARGETDIR
"\\Common\\afs_config_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
435 { TARGETDIR
"\\Common\\afs_cpa_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
436 { TARGETDIR
"\\Common\\afs_shl_ext_????.dll", SERVER
| CLIENT
| LCLIENT
| CC
},
437 { TARGETDIR
"\\Common\\afs-nt.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
438 { TARGETDIR
"\\Common\\afs-nt.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
439 { TARGETDIR
"\\Common\\taafssvrmgr.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
440 { TARGETDIR
"\\Common\\taafssvrmgr.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
441 { TARGETDIR
"\\Common\\taafsusrmgr.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
442 { TARGETDIR
"\\Common\\taafsusrmgr.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
443 { TARGETDIR
"\\Common\\afs-cc.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
444 { TARGETDIR
"\\Common\\afs-cc.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
445 { TARGETDIR
"\\Common\\afs-light.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
446 { TARGETDIR
"\\Common\\afs-light.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
447 { TARGETDIR
"\\Common\\taafscfg.cnt", SERVER
| CLIENT
| LCLIENT
| CC
},
448 { TARGETDIR
"\\Common\\taafscfg.hlp", SERVER
| CLIENT
| LCLIENT
| CC
},
449 { TARGETDIR
"\\Client\\PROGRAM\\afs_shl_ext.dll", CLIENT
| LCLIENT
},
450 { TARGETDIR
"\\Client\\PROGRAM\\libafsconf.dll", CLIENT
| LCLIENT
},
451 { TARGETDIR
"\\Client\\PROGRAM\\afslogon.dll", CLIENT
},
452 { TARGETDIR
"\\Client\\PROGRAM\\afslog95.dll", LCLIENT
},
453 { TARGETDIR
"\\Control Center\\TaAfsAdmSvr.exe", CC
},
454 { WINSYSDIR
"\\afs_cpa.cpl", CLIENT
| LCLIENT
| CC
},
455 { WINSYSDIR
"\\afsserver.cpl", SERVER
},
456 { TARGETDIR
"\\Common\\afsdcell.ini", CLIENT
| LCLIENT
| CC
},
457 { TARGETDIR
"\\Documentation\\Html\\banner.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
458 { TARGETDIR
"\\Documentation\\Html\\books.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
459 { TARGETDIR
"\\Documentation\\Html\\bot.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
460 { TARGETDIR
"\\Documentation\\Html\\index.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
461 { TARGETDIR
"\\Documentation\\Html\\index.htm", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
462 { TARGETDIR
"\\Documentation\\Html\\next.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
463 { TARGETDIR
"\\Documentation\\Html\\prev.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
464 { TARGETDIR
"\\Documentation\\Html\\toc.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
465 { TARGETDIR
"\\Documentation\\Html\\top.gif", SERVER
| CLIENT
| LCLIENT
| CC
| DOCS
},
466 { TARGETDIR
"\\Documentation\\Html\\ReleaseNotes\\relnotes.htm",
467 SERVER
| CLIENT
| LCLIENT
| CC
},
468 { TARGETDIR
"\\Documentation\\Html\\InstallGd\\afsnt35i.htm",
469 SERVER
| CLIENT
| LCLIENT
| CC
},
470 { 0, 0 } // End of list
475 * VARIABLES _________________________________________________________________
481 static BOOL bPreserveConfigInfo
;
482 static BOOL bSilentMode
;
483 static char *pszInstallDir
;
487 * FUNCTIONS _________________________________________________________________
491 static BOOL
UpgradeClientIntParm(HKEY hKey
, char *pszOldParm
, char *pszNewParm
)
494 LONG result
= ERROR_SUCCESS
;
496 nData
= GetPrivateProfileInt("AFS Client", pszOldParm
, -1, "afsd.ini");
498 result
= RegSetValueEx(hKey
, pszNewParm
, 0, REG_DWORD
, (BYTE
*)&nData
, sizeof(nData
));
500 return (result
== ERROR_SUCCESS
);
503 static BOOL
UpgradeClientStringParm(HKEY hKey
, char *pszOldParm
, char *pszNewParm
)
506 LONG result
= ERROR_SUCCESS
;
508 GetPrivateProfileString("AFS Client", pszOldParm
, "", szData
, sizeof(szData
), "afsd.ini");
510 result
= RegSetValueEx(hKey
, pszNewParm
, 0, REG_SZ
, (PBYTE
)szData
, strlen(szData
) + 1);
512 return (result
== ERROR_SUCCESS
);
515 int SUCALLCONV
Upgrade34ClientConfigInfo()
521 result
= RegOpenKeyAlt(AFSREG_NULL_KEY
, AFSREG_CLT_SVC_PARAM_KEY
, KEY_WRITE
, TRUE
, &hKey
, 0);
522 if (result
!= ERROR_SUCCESS
)
525 UpgradeClientIntParm(hKey
, "CacheSize", "CacheSize");
526 UpgradeClientIntParm(hKey
, "Stats", "Stats");
527 UpgradeClientIntParm(hKey
, "LogoffTokenTransfer", "LogoffTokenTransfer");
528 UpgradeClientIntParm(hKey
, "LogoffTokenTransferTimeout", "LogoffTokenTransferTimeout");
529 UpgradeClientIntParm(hKey
, "TrapOnPanic", "TrapOnPanic");
530 UpgradeClientIntParm(hKey
, "TraceBufferSize", "TraceBufferSize");
531 UpgradeClientIntParm(hKey
, "TraceOnShutdown", "TraceOnShutdown");
532 UpgradeClientIntParm(hKey
, "ReportSessionStartups", "ReportSessionStartups");
534 UpgradeClientStringParm(hKey
, "MountRoot", "MountRoot");
535 UpgradeClientStringParm(hKey
, "Cell", "Cell");
537 /* BlockSize to ChunkSize requires convertion */
538 nData
= GetPrivateProfileInt("AFS Client", "BlockSize", -1, "afsd.ini");
541 for (chunkSize
= 0; (1 << chunkSize
) < nData
; chunkSize
++);
542 (void) RegSetValueEx(hKey
, "ChunkSize", 0, REG_DWORD
, (BYTE
*)&chunkSize
, sizeof(chunkSize
));
550 int SUCALLCONV
Eradicate34Client()
552 if (Client34Eradicate(TRUE
) != ERROR_SUCCESS
)
558 // This function was written a long time ago by Mike Comer for use by the
559 // original DFS Client for NT install program.
560 int SUCALLCONV
CheckIfAdmin(void)
562 HANDLE token
= INVALID_HANDLE_VALUE
;
566 TOKEN_PRIMARY_GROUP
*pgroup
;
567 TOKEN_GROUPS
*groups
;
571 PSID AdministratorSID
= NULL
;
572 SID_IDENTIFIER_AUTHORITY authority
= SECURITY_NT_AUTHORITY
;
574 // allocate the SID for the Administrators group
575 if (!AllocateAndInitializeSid(&authority
, 2, SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &AdministratorSID
)) {
576 status
= GetLastError();
580 // open the process token
581 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ
, &token
)) {
582 status
= GetLastError();
583 token
= INVALID_HANDLE_VALUE
;
587 // check primary group first
588 buffer
= GlobalAlloc(GMEM_FIXED
, sizeof(TOKEN_PRIMARY_GROUP
));
593 bufLength
= sizeof(TOKEN_PRIMARY_GROUP
);
595 if (!GetTokenInformation(token
, TokenPrimaryGroup
, buffer
, bufLength
, &realBufLength
)) {
596 if (realBufLength
> bufLength
) {
599 bufLength
= realBufLength
;
600 buffer
= GlobalAlloc(GMEM_FIXED
, realBufLength
);
612 pgroup
= (TOKEN_PRIMARY_GROUP
*)buffer
;
613 if (EqualSid(pgroup
->PrimaryGroup
, AdministratorSID
)) {
616 // okay, try the secondary groups
618 if (!GetTokenInformation(token
, TokenGroups
, buffer
, bufLength
, &realBufLength
)) {
619 if (realBufLength
> bufLength
) {
622 bufLength
= realBufLength
;
623 buffer
= GlobalAlloc(GMEM_FIXED
, realBufLength
);
636 // we have the list of groups here. Process them:
637 groups
= (TOKEN_GROUPS
*)buffer
;
638 for(groupCount
= 0; groupCount
< groups
->GroupCount
; groupCount
++) {
639 if (EqualSid(groups
->Groups
[groupCount
].Sid
, AdministratorSID
)) {
648 if (token
!= INVALID_HANDLE_VALUE
) {
656 if (AdministratorSID
) {
657 FreeSid(AdministratorSID
);
663 static void SetSharedFileRefCount(char *pszFile
, int nRefCount
)
668 result
= RegOpenKeyAlt(AFSREG_NULL_KEY
, MS_SHARED_FILES_KEY
, KEY_WRITE
, FALSE
, &hKey
, 0);
669 if (result
!= ERROR_SUCCESS
)
673 RegDeleteValue(hKey
, pszFile
);
675 RegSetValueEx(hKey
, pszFile
, 0, REG_DWORD
, (BYTE
*)&nRefCount
, sizeof(int));
680 static char *GetTimeStamp()
682 char szTime
[64], szDate
[64];
683 static char szTimeDate
[128];
688 sprintf(szTimeDate
, "[%s %s] ", szTime
, szDate
);
693 int SUCALLCONV
WriteToInstallErrorLog(char *pszMsg
)
695 static BOOL bWritten
= FALSE
;
698 // On the first write, recreate the file
699 fp
= fopen(INSTALL_ERROR_LOG_NAME
, bWritten
? "a" : "w");
703 fprintf(fp
, "%s%s\r\n", GetTimeStamp(), pszMsg
);
712 static void WriteToUninstallErrorLog(char *pszMsg
)
714 static BOOL bWritten
= FALSE
;
717 // On the first write, recreate the file
718 fp
= fopen(UNINSTALL_ERROR_LOG_NAME
, bWritten
? "a" : "w");
722 fprintf(fp
, "%s%s\r\n", GetTimeStamp(), pszMsg
);
729 static char *LoadResString(UINT uID
)
731 static char str
[256];
732 GetString (str
, uID
);
736 static void ShowError(UINT nResID
, LONG nError
)
744 psz
= LoadResString(nResID
);
748 sprintf(szErr
, "unknown error msg (Msg ID = %d)", nResID
);
750 psz
= LoadResString(IDS_INSTALLATION_FAILURE
);
751 strcpy(szPrompt
, psz
? psz
: "An error has occurred: %s (Last Error = %ld).");
753 sprintf(szMsg
, szPrompt
, szErr
, nError
);
755 psz
= LoadResString(IDS_TITLE
);
756 strcpy(szTitle
, psz
? psz
: "AFS");
759 WriteToUninstallErrorLog(szMsg
);
761 MessageBox(hDlg
, szMsg
, szTitle
, MB_OK
);
764 static int ShowMsg(UINT nResID
, int nType
)
769 psz
= LoadResString(IDS_TITLE
);
770 strcpy(szTitle
, psz
? psz
: "AFS");
772 return MessageBox(hDlg
, LoadResString(nResID
), szTitle
, nType
);
775 static char *GetAppInstallDir(struct APPINFO
*pApp
, BOOL bRemembered
)
780 static char szInstallDir
[256];
785 pszKey
= bRemembered
? UNINSTALL_TEMP_INFO_KEY
: pApp
->regInstallDir
.pszKey
;
786 pszValue
= bRemembered
? INSTALL_DIR_VALUE_NAME
: pApp
->regInstallDir
.pszValue
;
788 dwSize
= sizeof(szInstallDir
);
790 nResult
= RegOpenKeyAlt(AFSREG_NULL_KEY
, pszKey
, KEY_READ
, FALSE
, &hKey
, 0);
791 if (nResult
== ERROR_SUCCESS
) {
792 nResult
= RegQueryValueEx(hKey
, pszValue
, 0, &dwType
, (PBYTE
)szInstallDir
, &dwSize
);
796 if (nResult
!= ERROR_SUCCESS
) {
797 ShowError(IDS_CANT_DETERMINE_APP_PATH
, nResult
);
801 FilepathNormalizeEx(szInstallDir
, FPN_BACK_SLASHES
);
806 static BOOL
DoesRegKeyExist(char *pszKey
)
811 nResult
= RegOpenKeyAlt(AFSREG_NULL_KEY
, pszKey
, KEY_READ
, FALSE
, &hKey
, 0);
812 if (nResult
== ERROR_SUCCESS
) {
820 static BOOL
IsAppInstalled(struct APPINFO
*pApp
)
822 return DoesRegKeyExist(pApp
->pszAppKey
);
825 static void BuildShortPath(char *pszShortPath
, UINT nShortPathLen
, char *pszInstallDir
, char *pszPath
)
827 strncpy(pszShortPath
, pszInstallDir
, nShortPathLen
);
828 strncat(pszShortPath
, pszPath
, nShortPathLen
);
830 GetShortPathName(pszShortPath
, pszShortPath
, nShortPathLen
);
833 static BOOL
IsWin95()
835 OSVERSIONINFO versionInformation
;
837 versionInformation
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
839 GetVersionEx(&versionInformation
);
841 if ((versionInformation
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) &&
842 (versionInformation
.dwMinorVersion
== 0))
850 OSVERSIONINFO versionInformation
;
852 versionInformation
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
854 GetVersionEx(&versionInformation
);
856 if ((versionInformation
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
) &&
857 (versionInformation
.dwMinorVersion
== 10))
863 static BOOL
IsServiceInstalled(char *pszServiceKey
)
867 if (RegOpenKeyAlt(0, pszServiceKey
, KEY_READ
, FALSE
, &hKey
, 0) == ERROR_SUCCESS
) {
875 // If this fails in anyway we just return. No error is displayed.
876 static void MakeSureServiceDoesNotExist(char *pszName
)
878 SC_HANDLE hServer
= 0, hSCM
= 0;
879 SERVICE_STATUS status
;
881 hSCM
= OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE
);
883 hServer
= OpenService(hSCM
, pszName
, SERVICE_ALL_ACCESS
| DELETE
);
885 if (QueryServiceStatus(hServer
, &status
)) {
886 if (status
.dwCurrentState
!= SERVICE_STOPPED
) {
887 if (!ControlService(hServer
, SERVICE_CONTROL_STOP
, &status
)) {
888 CloseServiceHandle(hServer
);
889 CloseServiceHandle(hSCM
);
895 // Try to delete even if status query fails
896 DeleteService(hServer
);
901 CloseServiceHandle(hServer
);
903 CloseServiceHandle(hSCM
);
906 static int InstallService(char *pszName
, char *pszDependOn
, char *pszDisplayName
, char *pszServicePath
, BOOL bInteractive
)
908 SC_HANDLE hServer
= 0, hSCM
;
909 BOOL bRestoreOldConfig
= FALSE
;
911 if (!AddToProviderOrder(AFSREG_CLT_SVC_NAME
)) {
912 ShowError(ERROR_FILE_NOT_FOUND
, GetLastError());
915 hSCM
= OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE
);
917 ShowError(IDS_SCM_OPEN_FAILED
, GetLastError());
921 /* This code is not used, but it could be handy in the future so I am keeping it here.
923 // If the service exists, then we (most probably) are in the middle of an upgrade or reinstall.
924 bRestoreOldConfig = IsServiceInstalled(pszName);
926 if (bRestoreOldConfig) {
927 hServer = OpenService(hSCM, pszName, SERVICE_ALL_ACCESS);
928 if (!hServer || !ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
929 ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED, GetLastError());
930 bRestoreOldConfig = FALSE;
931 // Fall through to service creation below
936 if (!bRestoreOldConfig
) {
939 // If the service already exists, the create call will fail. This can
940 // happen if uninstall failed (which is not infrequent). Making sure the
941 // service does not exist makes it easier for a user to install over top of
942 // a previously failed uninstall.
943 MakeSureServiceDoesNotExist(pszName
);
945 dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
947 dwServiceType
|= SERVICE_INTERACTIVE_PROCESS
;
949 hServer
= CreateService(hSCM
, pszName
, pszDisplayName
,
950 SERVICE_ALL_ACCESS
, dwServiceType
, SERVICE_AUTO_START
,
951 SERVICE_ERROR_NORMAL
, pszServicePath
, 0, 0, "RPCSS\0Netbios\0\0", 0, 0);
954 ShowError(IDS_SERVICE_CREATE_FAILED
, GetLastError());
958 CloseServiceHandle(hServer
);
960 CloseServiceHandle(hSCM
);
965 int SUCALLCONV
InstallServerService(char *pszServicePath
)
967 return InstallService(appServer
.pszSvcName
, 0, appServer
.pszSvcDisplayName
, pszServicePath
, TRUE
);
970 int SUCALLCONV
InstallClientService(char *pszServicePath
)
972 return InstallService(appClient
.pszSvcName
, appClient
.pszSvcDependOn
, appClient
.pszSvcDisplayName
, pszServicePath
, FALSE
);
975 static int UninstallService(struct APPINFO
*pAppInfo
)
977 SC_HANDLE hServer
, hSCM
;
978 SERVICE_STATUS status
;
980 BOOL bServer
= FALSE
;
981 BOOL bShowingProgressDlg
= FALSE
;
983 if (!RemoveFromProviderOrder(AFSREG_CLT_SVC_NAME
)) {
984 ShowError(ERROR_FILE_NOT_FOUND
, GetLastError());
987 hSCM
= OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE
);
989 ShowError(IDS_SCM_OPEN_FAILED
, GetLastError());
993 hServer
= OpenService(hSCM
, pAppInfo
->pszSvcName
, SERVICE_ALL_ACCESS
| DELETE
);
995 ShowError(IDS_SERVICE_OPEN_FAILED
, GetLastError());
996 CloseServiceHandle(hSCM
);
1000 if (!QueryServiceStatus(hServer
, &status
)) {
1001 ShowError(IDS_SERVICE_QUERY_FAILED
, GetLastError());
1002 CloseServiceHandle(hServer
);
1003 CloseServiceHandle(hSCM
);
1007 if (status
.dwCurrentState
!= SERVICE_STOPPED
) {
1008 if (pAppInfo
->nServiceShutdownMsgID
) {
1009 if (!bSilentMode
&& (ShowMsg(pAppInfo
->nServiceShutdownMsgID
, MB_YESNO
| MB_ICONQUESTION
) == IDNO
)) {
1010 CloseServiceHandle(hServer
);
1011 CloseServiceHandle(hSCM
);
1017 bShowingProgressDlg
= ShowProgressDialog(LoadResString(pAppInfo
->nServiceShutdownProgressMsgID
));
1019 if (!ControlService(hServer
, SERVICE_CONTROL_STOP
, &status
)) {
1020 if (bShowingProgressDlg
)
1021 HideProgressDialog();
1022 ShowError(IDS_SERVICE_STOP_FAILED
, GetLastError());
1023 CloseServiceHandle(hServer
);
1024 CloseServiceHandle(hSCM
);
1029 // Wait for the service to stop
1030 while (status
.dwCurrentState
!= SERVICE_STOPPED
) {
1031 // I stopped waiting on dwWaitHint because it seemed the wait hint was too long.
1032 // The service would be stopped but we'd still be asleep for a long time yet.
1033 Sleep(5000); //status.dwWaitHint);
1035 if (!QueryServiceStatus(hServer
, &status
)) {
1036 if (bShowingProgressDlg
)
1037 HideProgressDialog();
1038 ShowError(IDS_SERVICE_QUERY_FAILED
, GetLastError());
1039 CloseServiceHandle(hServer
);
1040 CloseServiceHandle(hSCM
);
1045 // The service has been stopped
1046 if (bShowingProgressDlg
)
1047 HideProgressDialog();
1049 // This code to disable the service may be of use some day so I am keeping it here.
1050 // bOk = ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_DISABLED, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0);
1052 bOk
= DeleteService(hServer
);
1055 ShowError(IDS_SERVICE_DELETE_FAILED
, GetLastError());
1057 CloseServiceHandle(hServer
);
1058 CloseServiceHandle(hSCM
);
1060 return (bOk
? 0 : -1);
1063 int SUCALLCONV
AddToNetworkProviderOrder(char *pszWhatToAdd
)
1065 return AddToProviderOrder(pszWhatToAdd
) ? 0 : -1;
1068 static int RemoveFromNetworkProviderOrder(char *pszWhatToDel
)
1070 return RemoveFromProviderOrder(pszWhatToDel
) ? 0 : -1;
1073 int SUCALLCONV
AddToPath(char *pszPath
)
1075 return AddToSystemPath(pszPath
) ? 0 : -1;
1078 static int RemoveFromPath(char *pszPath
)
1080 return RemoveFromSystemPath(pszPath
) ? 0 : -1;
1083 static void RemoveFiles(char *pszFileSpec
)
1085 struct _finddata_t fileinfo
;
1087 char szDel
[MAX_PATH
];
1088 char szDir
[MAX_PATH
];
1091 strcpy(szDir
, pszFileSpec
);
1092 p
= strrchr(szDir
, '\\');
1096 hSearch
= _findfirst(pszFileSpec
, &fileinfo
);
1101 if ((strcmp(fileinfo
.name
, ".") != 0) && (strcmp(fileinfo
.name
, "..") != 0)) {
1102 sprintf(szDel
, "%s\\%s", szDir
, fileinfo
.name
);
1106 if (_findnext(hSearch
, &fileinfo
) == -1)
1110 _findclose(hSearch
);
1113 static void RemoveDir(char *pszDir
)
1115 char szFileSpec
[MAX_PATH
];
1117 sprintf(szFileSpec
, "%s\\*.*", pszDir
);
1119 RemoveFiles(szFileSpec
);
1120 RemoveDirectory(pszDir
);
1123 static void RemoveRegValues(struct REGVALUE
*pRegValues
)
1125 struct REGVALUE
*pCurValue
;
1132 for (pCurValue
= pRegValues
; pCurValue
->pszKey
; pCurValue
++) {
1133 nResult
= RegOpenKeyAlt(AFSREG_NULL_KEY
, pCurValue
->pszKey
, KEY_ALL_ACCESS
, FALSE
, &hKey
, 0);
1135 if (nResult
== ERROR_SUCCESS
) {
1136 nResult
= RegDeleteValue(hKey
, pCurValue
->pszValue
);
1140 if (nResult
!= ERROR_SUCCESS
)
1141 ShowError(IDS_REG_DELETE_VALUE_ERROR
, nResult
);
1145 static BOOL
UninstallCredsTool()
1147 int nResult
= WinExec("afscreds /uninstall", SW_HIDE
);
1149 if (nResult
<= 31) {
1150 if (nResult
!= ERROR_FILE_NOT_FOUND
)
1151 ShowError(IDS_CANT_UNINSTALL_AFSCREDS
, nResult
);
1154 // Always return true. We don't want the uninstall to completely fail just
1155 // because the creds tool didn't uninstall.
1160 static char *GetTempDir()
1163 static char szTempDir
[MAX_PATH
];
1165 result
= GetTempPath(sizeof(szTempDir
) - 1, szTempDir
);
1172 static char *GetRootInstallDir()
1175 static char szRootInstallDir
[MAX_PATH
] = "";
1177 if (szRootInstallDir
[0] == 0) {
1178 strcpy(szRootInstallDir
, pszInstallDir
);
1180 // Strip off the app specific part of the install dir
1181 psz
= strrchr(szRootInstallDir
, '\\');
1186 return szRootInstallDir
;
1189 static BOOL
ClientSpecificUninstall()
1193 // This function needs to do two things. First it needs to see if the server is
1194 // installed, and if it is, ask the user if they really want to uninstall the
1195 // client given that the server needs the client. Second, if we are uninstalling
1196 // the client, we need to uninstall the creds tool.
1199 if (IsAppInstalled(&appServer
)) {
1200 nChoice
= ShowMsg(IDS_CLIENT_NEEDED_BY_SERVER
, MB_ICONQUESTION
| MB_YESNO
);
1201 if (nChoice
== IDNO
)
1202 return FALSE
; // Cancel the uninstall
1206 UninstallCredsTool();
1211 static struct APPINFO
*GetApp()
1213 #ifdef SERVER_UNINST
1218 return &appControlCenter
;
1219 #elif LIGHT_CLIENT_UNINST
1220 return &appLightClient
;
1228 static void RememberInstallDir(char *pszInstallDir
)
1232 // We remember the install dir so that when the UninstUninitialize function is called
1233 // by the InstallShield uninstaller, we can find out where we were installed to. We
1234 // have to do this because by the time that function is called, the registry values
1235 // created at install time are already gone. We need to be able to find out where we
1236 // were installed so we can clean up anything IS couldn't uninstall. If this fails in
1237 // any way then we don't care. The only consequence is that some junk might be left on
1238 // the users' system after an uninstall.
1240 LONG result
= RegOpenKeyAlt(AFSREG_NULL_KEY
, UNINSTALL_TEMP_INFO_KEY
, KEY_WRITE
, TRUE
, &hKey
, 0);
1241 if (result
!= ERROR_SUCCESS
)
1244 RegSetValueEx(hKey
, INSTALL_DIR_VALUE_NAME
, 0, REG_SZ
, (PBYTE
)pszInstallDir
, strlen(pszInstallDir
) + 1);
1249 int SUCALLCONV
SetSilentMode()
1256 static char *GetWinDir()
1258 static char szWinDir
[MAX_PATH
] = "";
1261 GetWindowsDirectory(szWinDir
, sizeof(szWinDir
));
1266 static char *GetWinSysDir()
1268 static char szWinSysDir
[MAX_PATH
] = "";
1270 if (!szWinSysDir
[0])
1271 GetSystemDirectory(szWinSysDir
, sizeof(szWinSysDir
));
1276 static char *GetLocaleID()
1278 static char szID
[25] = "";
1281 LCID dwID
= GetSystemDefaultLCID();
1283 // Nuke the high word. It contains a sort ID.
1286 // Convert locale ID to a string
1287 itoa(dwID
, szID
, 10);
1289 // This thing should never be more than LOCALE_ID_LEN characters long.
1290 szID
[LOCALE_ID_LEN
] = 0;
1296 static char *ExpandPath(char *pszFile
)
1298 static char szPath
[MAX_PATH
];
1303 // Convert a path containing TARGETDIR, WINDIR, or WINSYSDIR to a
1304 // real path in the file system. One of these MUST be the start of
1305 // the file path passed in. Also convert the string ???? to an
1306 // actual locale number.
1307 if (strncmp(pszFile
, TARGETDIR
, strlen(TARGETDIR
)) == 0)
1308 strcpy(szPath
, GetRootInstallDir());
1309 else if (strncmp(pszFile
, WINDIR
, strlen(WINDIR
)) == 0)
1310 strcpy(szPath
, GetWinDir());
1311 else if (strncmp(pszFile
, WINSYSDIR
, strlen(WINSYSDIR
)) == 0)
1312 strcpy(szPath
, GetWinSysDir());
1315 psz
= strchr(pszFile
, '\\');
1317 strcat(szPath
, psz
);
1319 strcpy(szPath
, pszFile
);
1321 // Is this a language dll?
1322 psz
= strstr(szPath
, "????.");
1324 // If it is, replace ???? with the locale number
1326 strncpy(psz
, GetLocaleID(), LOCALE_ID_LEN
);
1331 static BOOL
FileNeededByOtherApp(struct APPINFO
*pApp
, struct FILEINFO
*pFileInfo
)
1333 // If the file is used by the server, the app being uninstalled is not the server, and
1334 // the server is installed, then this file is used by another app.
1336 if ((pFileInfo
->nUsedBy
& LCLIENT
) && (pApp
!= &appLightClient
) && IsAppInstalled(&appLightClient
))
1341 if ((pFileInfo
->nUsedBy
& SERVER
) && (pApp
!= &appServer
) && IsAppInstalled(&appServer
))
1344 if ((pFileInfo
->nUsedBy
& CLIENT
) && (pApp
!= &appClient
) && IsAppInstalled(&appClient
))
1347 if ((pFileInfo
->nUsedBy
& CC
) && (pApp
!= &appControlCenter
) && IsAppInstalled(&appControlCenter
))
1353 static void DeleteInUseFiles(struct APPINFO
*pAppInfo
, struct FILEINFO
*pFileInfo
)
1355 char szSrcPath
[MAX_PATH
];
1356 char szDestPath
[MAX_PATH
];
1357 char szTempDir
[MAX_PATH
];
1360 // If some app's file has been loaded before the app is uninstalled, then
1361 // when an uninstall is attempted, the application and all of the dlls that
1362 // its uses will be in use and IS will not be able to delete them. Normally this
1363 // is not a problem because IS will tell the user to reboot to finish the uninstall.
1364 // However, we must support the ability to perform a silent uninstall followed
1365 // immediatly by an install of the same product to the same directories. If we let
1366 // IS handle the uninstall of these files, this is not possible. The reason is that
1367 // when IS fails to remove these in use files, it marks them for deletion after the
1368 // next reboot, which is fine. Unfortunately, it leaves them in the dirs they were
1369 // installed to. So if we don't immediately reboot and perform an install to the
1370 // same dirs, once a reboot is performed, those files get deleted and we have a
1371 // broken installation.
1373 // What we will do to fix all of this, is when the client is uninstalled, but
1374 // before IS does anything, we will move the in use files and associated dlls
1375 // into the temp dir and mark them for delete after a reboot. Then an install
1376 // that follows will succeed.
1378 // Delete the files that may be in use. If they are we actually move
1379 // them to the temp dir and mark them for deletion after the next reboot.
1380 for (ii
= 0; pFileInfo
[ii
].pszName
!= 0; ii
++) {
1381 // Get the source path
1382 strcpy(szSrcPath
, ExpandPath(pFileInfo
[ii
].pszName
));
1384 // Only delete the file if it is not used by some other app
1385 if (FileNeededByOtherApp(pAppInfo
, &pFileInfo
[ii
]))
1388 // If the file doesn't exist then go on to the next file.
1389 if (_access(szSrcPath
, 0) != 0)
1392 // See if we can do a regular delete of the file
1393 if (DeleteFile(szSrcPath
)) {
1394 SetSharedFileRefCount(szSrcPath
, 0);
1398 // Get a temp dir that is on the same drive as the src path.
1399 // We can't move an in use file to a different drive.
1400 strcpy(szTempDir
, GetTempDir());
1401 if (szTempDir
[0] != szSrcPath
[0]) {
1402 // Get the drive, colon, and slash of the src path
1403 strncpy(szTempDir
, szSrcPath
, 3);
1407 // Get the dest path - we will rename the file during the move
1408 GetTempFileName(szTempDir
, "AFS", 0, szDestPath
);
1410 // Move from source to dest, marking the file for deletion after a reboot
1412 if (MoveFile(szSrcPath
, szDestPath
)) {
1413 WritePrivateProfileString("rename", szSrcPath
, szDestPath
, "wininit.ini");
1414 SetSharedFileRefCount(szSrcPath
, 0);
1416 } else { // WinNT or Win98
1417 if (MoveFileEx(szSrcPath
, szDestPath
, MOVEFILE_REPLACE_EXISTING
)) {
1418 SetFileAttributes(szDestPath
, FILE_ATTRIBUTE_NORMAL
);
1419 MoveFileEx(szDestPath
, 0, MOVEFILE_DELAY_UNTIL_REBOOT
);
1420 SetSharedFileRefCount(szSrcPath
, 0);
1426 // Delete a directory and all its files and subdirectories - Yee haaa!
1427 static void RemoveDirectoryTree(char *pszDir
)
1430 WIN32_FIND_DATA findFileData
;
1431 char szSpec
[MAX_PATH
];
1432 char szSubFileOrDir
[MAX_PATH
];
1435 sprintf(szSpec
, "%s\\*.*", pszDir
);
1437 // First delete the contents of the dir
1438 hFind
= FindFirstFile(szSpec
, &findFileData
);
1439 bContinue
= (hFind
!= INVALID_HANDLE_VALUE
);
1442 if ((strcmp(findFileData
.cFileName
, ".") != 0) && (strcmp(findFileData
.cFileName
, "..") != 0)) {
1443 sprintf(szSubFileOrDir
, "%s\\%s", pszDir
, findFileData
.cFileName
);
1445 if (findFileData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1446 RemoveDirectoryTree(szSubFileOrDir
);
1448 DeleteFile(szSubFileOrDir
);
1451 bContinue
= FindNextFile(hFind
, &findFileData
);
1456 // Now remove the dir
1457 RemoveDirectory(pszDir
);
1460 static char *GetStartMenuRoot()
1469 static char szStartMenuRoot
[MAX_PATH
] = "";
1471 if (szStartMenuRoot
[0] == 0) {
1472 dwSize
= sizeof(szStartMenuRoot
);
1475 pszKey
= WINNT_START_MENU_REG_KEY
;
1476 pszValue
= WINNT_START_MENU_REG_VALUE
;
1478 pszKey
= WIN9X_START_MENU_REG_KEY
;
1479 pszValue
= WIN9X_START_MENU_REG_VALUE
;
1482 nResult
= RegOpenKeyAlt(AFSREG_NULL_KEY
, pszKey
, KEY_READ
, FALSE
, &hKey
, 0);
1483 if (nResult
== ERROR_SUCCESS
) {
1484 nResult
= RegQueryValueEx(hKey
, pszValue
, 0, &dwType
, (PBYTE
)szStartMenuRoot
, &dwSize
);
1488 if (nResult
!= ERROR_SUCCESS
)
1492 FilepathNormalizeEx(szStartMenuRoot
, FPN_BACK_SLASHES
);
1494 return szStartMenuRoot
;
1497 static char *GetAfsStartMenuRoot()
1499 static char szAfsStartMenuRoot
[MAX_PATH
] = "";
1500 char *pszStartMenuRoot
;
1502 if (szAfsStartMenuRoot
[0] == 0) {
1503 pszStartMenuRoot
= GetStartMenuRoot();
1504 if (!pszStartMenuRoot
)
1508 sprintf(szAfsStartMenuRoot
, "%s\\IBM WebSphere\\Performance Pack\\AFS", pszStartMenuRoot
);
1510 sprintf(szAfsStartMenuRoot
, "%s\\IBM AFS", pszStartMenuRoot
);
1513 return szAfsStartMenuRoot
;
1516 static BOOL
IsADir(char *pszName
)
1518 struct _stat statbuf
;
1520 if (_stat(pszName
, &statbuf
) < 0)
1523 return statbuf
.st_mode
& _S_IFDIR
;
1526 static void DeleteStartMenuEntries(char *pszEntries
)
1528 char szStartMenuPath
[MAX_PATH
];
1529 char *pszAfsStartMenuRoot
;
1532 pszAfsStartMenuRoot
= GetAfsStartMenuRoot();
1534 if (!pszAfsStartMenuRoot
)
1537 for (pszCurEntry
= pszEntries
; *pszCurEntry
; pszCurEntry
+= strlen(pszCurEntry
) + 1) {
1538 sprintf(szStartMenuPath
, "%s\\%s", pszAfsStartMenuRoot
, pszCurEntry
);
1539 if (IsADir(szStartMenuPath
))
1540 RemoveDirectoryTree(szStartMenuPath
);
1542 DeleteFile(szStartMenuPath
);
1546 static void RefreshStartMenu()
1548 char *pszAfsStartMenuRoot
;
1549 char szTemp
[MAX_PATH
];
1551 pszAfsStartMenuRoot
= GetAfsStartMenuRoot();
1552 if (!pszAfsStartMenuRoot
)
1555 sprintf(szTemp
, "%s - Refresh Attempt", pszAfsStartMenuRoot
);
1557 // Deleting items from below the root level of the start menu does not
1558 // cause it to refresh. In order that users can see changes without
1559 // rebooting we will temporarily rename our root most entry, which
1560 // does cause a refresh of the start menu.
1561 MoveFileEx(pszAfsStartMenuRoot
, szTemp
, MOVEFILE_REPLACE_EXISTING
);
1562 MoveFileEx(szTemp
, pszAfsStartMenuRoot
, MOVEFILE_REPLACE_EXISTING
);
1565 static BOOL
PreserveConfigInfo(struct APPINFO
*pApp
)
1568 char szDestKey
[256];
1571 bPreserveConfigInfo
= TRUE
;
1573 // If not in silent mode, ask user if they want to preserve the cfg info
1575 int nChoice
= ShowMsg(pApp
->nPreserveConfigInfoMsgID
, MB_ICONQUESTION
| MB_YESNOCANCEL
);
1576 if (nChoice
== IDCANCEL
)
1577 return FALSE
; // Cancel the uninstall
1578 else if (nChoice
== IDNO
) {
1579 bPreserveConfigInfo
= FALSE
; // User doesn't want to preserve the config info
1584 // Copy each reg key (and all of its subkeys and values) to another place in the registry.
1585 for (pszRegKey
= pApp
->pszRegKeysToPreserve
; *pszRegKey
; pszRegKey
+= strlen(pszRegKey
) + 1) {
1586 if (!DoesRegKeyExist(pszRegKey
))
1589 // Create the destination path for the copy
1590 sprintf(szDestKey
, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
, pszRegKey
);
1593 result
= RegDupKeyAlt(pszRegKey
, szDestKey
);
1595 if ((result
!= ERROR_SUCCESS
) && (result
!= ERROR_FILE_NOT_FOUND
)) {
1596 // If the copy failed, then delete any copies that succeeded
1597 sprintf(szDestKey
, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
);
1598 RegDeleteEntryAlt(szDestKey
, REGENTRY_KEY
);
1603 // Remember the integrated login setting if this app supports that and it was turned on
1604 if (pApp
->pszNetworkProviderOrder
) {
1605 // Was integerated login turned on?
1607 bOk
= InNetworkProviderOrder(pApp
->pszNetworkProviderOrder
, &bOn
);
1610 sprintf(szDestKey
, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
);
1611 result
= RegOpenKeyAlt(AFSREG_NULL_KEY
, szDestKey
, KEY_WRITE
, TRUE
, &hKey
, 0);
1612 // The existance of the key is a flag indicating that integrated login was turned on
1618 if ((result
== ERROR_SUCCESS
) || bSilentMode
)
1619 return TRUE
; // Continue with uninstall
1621 // Report the error and ask the user if they want to continue the uninstall
1622 return (ShowMsg(IDS_SAVE_OF_CONFIG_INFO_FAILED
, MB_ICONEXCLAMATION
| MB_YESNO
) == IDYES
);
1625 int SUCALLCONV
RestoreConfigInfo(int nApp
)
1629 struct APPINFO
*pApp
= 0;
1630 BOOL bError
= FALSE
;
1634 case SERVER
: pApp
= &appServer
; break;
1635 case CLIENT
: pApp
= &appClient
; break;
1636 case LCLIENT
: pApp
= &appLightClient
; break;
1637 case CC
: pApp
= &appControlCenter
; break;
1643 // Copy each reg key (and all of its subkeys and values) back to its original place in the registry.
1644 for (pszRegKey
= pApp
->pszRegKeysToPreserve
; *pszRegKey
; pszRegKey
+= strlen(pszRegKey
) + 1) {
1645 // Create the source path for the copy
1646 sprintf(szSrcKey
, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
, pszRegKey
);
1648 if (!DoesRegKeyExist(szSrcKey
))
1651 // Try to restore as many of the keys as possible. Report any errors at the end.
1654 result
= RegDupKeyAlt(szSrcKey
, pszRegKey
);
1655 if ((result
!= ERROR_SUCCESS
) && (result
!= ERROR_FILE_NOT_FOUND
))
1659 // Restore integrated login if this app was using it
1660 if (pApp
->pszNetworkProviderOrder
) {
1661 // Check if integrated login was turned on. The IntegratedLogin key is a flag
1662 // telling us that it was on. If the key does not exist, integrated login was
1664 sprintf(szSrcKey
, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
);
1665 if (DoesRegKeyExist(szSrcKey
)) {
1666 if (!AddToProviderOrder(pApp
->pszNetworkProviderOrder
))
1671 // Remove our saved copies of the config info
1672 sprintf(szSrcKey
, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY
, pApp
->pszAppName
);
1673 RegDeleteEntryAlt(szSrcKey
, REGENTRY_KEY
);
1676 ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED
, 0);
1681 static BOOL
DoSubKeysExist(char *pszKey
)
1685 char *pszSubKeys
= 0;
1688 result
= RegOpenKeyAlt(AFSREG_NULL_KEY
, pszKey
, KEY_READ
, FALSE
, &hKey
, 0);
1689 if (result
!= ERROR_SUCCESS
)
1692 result
= RegEnumKeyAlt(hKey
, &pszSubKeys
);
1695 if (result
!= ERROR_SUCCESS
)
1708 * The following definitions are taken from richedit.h:
1712 #define EM_SETBKGNDCOLOR (WM_USER + 67) // from Richedit.h
1713 #define EM_STREAMIN (WM_USER + 73) // from Richedit.h
1714 #define SF_RTF 0x0002
1716 typedef DWORD (CALLBACK
*EDITSTREAMCALLBACK
)(DWORD dwCookie
, LPBYTE pbBuff
, LONG cb
, LONG
*pcb
);
1718 typedef struct _editstream
{
1719 DWORD dwCookie
; /* user value passed to callback as first parameter */
1720 DWORD dwError
; /* last error */
1721 EDITSTREAMCALLBACK pfnCallback
;
1728 DWORD CALLBACK
License_StreamText (DWORD dwCookie
, LPBYTE pbBuff
, LONG cb
, LONG
*pcb
)
1730 LPTSTR psz
= (LPTSTR
)dwCookie
;
1731 LONG cchAvail
= lstrlen(psz
);
1732 if ((*pcb
= min(cchAvail
, cb
)) != 0) {
1733 memcpy (pbBuff
, psz
, *pcb
);
1734 memmove (psz
, &psz
[*pcb
], cchAvail
- *pcb
+ 1);
1740 void License_OnInitDialog (HWND hDlg
, LPTSTR pszFile
)
1742 // Open the license file and shove its text in our RichEdit control
1745 if ((hFile
= CreateFile (pszFile
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
)) != INVALID_HANDLE_VALUE
) {
1748 if ((cbText
= GetFileSize (hFile
, NULL
)) != 0) {
1750 LPTSTR abText
= (LPTSTR
)GlobalAlloc (GMEM_FIXED
, cbText
+ 3);
1753 if (ReadFile (hFile
, abText
, cbText
, &cbRead
, NULL
)) {
1754 abText
[ cbRead
] = 0;
1757 memset (&Stream
, 0x00, sizeof(Stream
));
1758 Stream
.dwCookie
= (DWORD
)abText
;
1759 Stream
.pfnCallback
= License_StreamText
;
1761 SendDlgItemMessage (hDlg
, IDC_TEXT
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&Stream
);
1764 GlobalFree (abText
);
1767 CloseHandle (hFile
);
1770 // Make the control's background be gray
1772 SendDlgItemMessage (hDlg
, IDC_TEXT
, EM_SETBKGNDCOLOR
, FALSE
, (LPARAM
)GetSysColor(COLOR_BTNFACE
));
1775 BOOL CALLBACK
License_DlgProc (HWND hDlg
, UINT msg
, WPARAM wp
, LPARAM lp
)
1779 SetWindowLong (hDlg
, DWL_USER
, lp
);
1780 License_OnInitDialog (hDlg
, (LPTSTR
)lp
);
1784 switch (LOWORD(wp
)) {
1787 EndDialog (hDlg
, LOWORD(wp
));
1791 TCHAR szDir
[ MAX_PATH
];
1792 GetCurrentDirectory (MAX_PATH
, szDir
);
1793 ShellExecute (hDlg
, TEXT("print"), (LPTSTR
)GetWindowLong (hDlg
, DWL_USER
), NULL
, szDir
, SW_HIDE
);
1801 BOOL
FindAfsInstallationPathByComponent (LPTSTR pszInstallationPath
, LPTSTR pszComponent
)
1803 *pszInstallationPath
= 0;
1805 TCHAR szRegPath
[ MAX_PATH
];
1806 wsprintf (szRegPath
, TEXT("Software\\TransarcCorporation\\%s\\CurrentVersion"), pszComponent
);
1809 if (RegOpenKey (HKEY_LOCAL_MACHINE
, szRegPath
, &hk
) == 0) {
1810 DWORD dwType
= REG_SZ
;
1811 DWORD dwSize
= MAX_PATH
;
1813 if (RegQueryValueEx (hk
, TEXT("PathName"), NULL
, &dwType
, (PBYTE
)pszInstallationPath
, &dwSize
) == 0) {
1814 *(LPTSTR
)FindBaseFileName (pszInstallationPath
) = TEXT('\0');
1816 if (pszInstallationPath
[0] && (pszInstallationPath
[ lstrlen(pszInstallationPath
)-1 ] == TEXT('\\')))
1817 pszInstallationPath
[ lstrlen(pszInstallationPath
)-1 ] = TEXT('\0');
1823 return !!*pszInstallationPath
;
1826 BOOL
FindAfsInstallationPath (LPTSTR pszInstallationPath
)
1828 if (FindAfsInstallationPathByComponent (pszInstallationPath
, TEXT("AFS Client")))
1830 if (FindAfsInstallationPathByComponent (pszInstallationPath
, TEXT("AFS Control Center")))
1832 if (FindAfsInstallationPathByComponent (pszInstallationPath
, TEXT("AFS Server")))
1834 if (FindAfsInstallationPathByComponent (pszInstallationPath
, TEXT("AFS Supplemental Documentation")))
1839 HINSTANCE
LoadRichTextControl (void)
1842 if ((hInst
= LoadLibrary ("riched20.dll")) != NULL
)
1844 if ((hInst
= LoadLibrary ("riched32.dll")) != NULL
)
1846 if ((hInst
= LoadLibrary ("riched.dll")) != NULL
)
1848 if ((hInst
= LoadLibrary ("richedit.dll")) != NULL
)
1853 int SUCALLCONV
ShowLicense (char *pszTarget
, char *pszSource
)
1855 // If the license already lives on this user's machine, don't show
1856 // it again. This only has to be done if the user has never
1857 // accepted the license agreement before (it's part of the setup
1858 // program, so it gets installed if they've accepted it).
1860 // We were handed a relative path of the form:
1861 // Documentation/html/license.rtf
1863 // We'll need to find the AFS installation directory, in order to
1864 // find that Documentation subtree.
1866 BOOL fShowLicense
= TRUE
;
1868 TCHAR szInstallationPath
[ MAX_PATH
];
1869 if (FindAfsInstallationPath (szInstallationPath
)) {
1870 TCHAR szLicensePath
[ MAX_PATH
];
1871 wsprintf (szLicensePath
, TEXT("%s\\%s"), szInstallationPath
, pszTarget
);
1873 if (GetFileAttributes (szLicensePath
) != (DWORD
)-1) {
1874 fShowLicense
= FALSE
;
1878 // Before we can show the license file, we have to prepare the RichEdit
1879 // control. That means loading the appropriate library and calling its
1880 // initialization functions.
1882 HINSTANCE hRichEdit
;
1883 if ((hRichEdit
= LoadRichTextControl()) != NULL
) {
1885 // If we must show the license, do so now. This is a modal dialog,
1886 // so we'll know whether or not the user accepts the license.
1888 if (ModalDialogParam (IDD_LICENSE
, GetActiveWindow(), License_DlgProc
, (LPARAM
)pszSource
) == IDCANCEL
) {
1889 // The user rejected the license; fail setup
1893 FreeLibrary (hRichEdit
);
1896 // The user accepted the license, so we can continue with Setup.
1897 // The license file is installed as part of Setup.
1901 int SUCALLCONV
UninstInitialize(HWND hIS
, HINSTANCE hIS5
, long Reserved
)
1903 char szPath
[MAX_PATH
];
1904 struct APPINFO
*pAppInfo
;
1906 char *pszSubDir
= 0;
1910 bSilentMode
= !IsWindowVisible(hIS
);
1912 // Which app are we uninstalling?
1913 pAppInfo
= GetApp();
1915 ShowError(IDS_CANT_DETERMINE_PRODUCT
, 0);
1919 // Get the app's install dir
1920 pszInstallDir
= GetAppInstallDir(pAppInfo
, FALSE
);
1924 // If this app has a custom uninstall func, call it here
1925 if (pAppInfo
->pUninstallFunc
)
1926 if (!pAppInfo
->pUninstallFunc())
1929 if (pAppInfo
->pszRegKeysToPreserve
)
1930 if (!PreserveConfigInfo(pAppInfo
))
1933 // Unconfigure the service, if there is one for this app
1934 if (pAppInfo
->pszSvcKey
) {
1935 if (IsServiceInstalled(pAppInfo
->pszSvcKey
))
1936 if (UninstallService(pAppInfo
) == 1)
1940 RememberInstallDir(pszInstallDir
);
1942 DeleteInUseFiles(pAppInfo
, fileInfo
);
1944 // Remove the app's bin path from the system path
1945 if (pAppInfo
->pszBinPath
) {
1946 BuildShortPath(szPath
, sizeof(szPath
), pszInstallDir
, pAppInfo
->pszBinPath
);
1947 RemoveFromPath(szPath
);
1950 // Remove entry from NetworkProvider\Order key in registry
1951 if (pAppInfo
->pszNetworkProviderOrder
)
1952 RemoveFromNetworkProviderOrder(pAppInfo
->pszNetworkProviderOrder
);
1954 // Remove any generated subdirectories
1955 if (!bPreserveConfigInfo
&& pAppInfo
->pszDirsToDel
) {
1956 for (pszSubDir
= pAppInfo
->pszDirsToDel
; *pszSubDir
; pszSubDir
+= strlen(pszSubDir
) + 1)
1957 RemoveDir(ExpandPath(pszSubDir
));
1960 // Remove any generated files
1961 if (!bPreserveConfigInfo
&& pAppInfo
->pszFilesToDel
) {
1962 for (pszFile
= pAppInfo
->pszFilesToDel
; *pszFile
; pszFile
+= strlen(pszFile
) + 1)
1963 RemoveFiles(ExpandPath(pszFile
));
1966 // Remove any registry values that IS can't handle
1967 RemoveRegValues(pAppInfo
->pRegValues
);
1969 RemoveRegValues(pAppInfo
->pWinNTRegValues
);
1971 RemoveRegValues(pAppInfo
->pWin9XRegValues
);
1973 // Remove the start menu entries for this app
1974 if (pAppInfo
->pszStartMenuEntries
) {
1975 DeleteStartMenuEntries(pAppInfo
->pszStartMenuEntries
);
1979 // Remove the install dir
1980 RemoveDirectory(pszInstallDir
);
1985 void SUCALLCONV
UninstUnInitialize(HWND hIS
, HINSTANCE hIS5
, long Reserved
)
1987 char *pszInstallDir
;
1988 char szDirPath
[MAX_PATH
];
1990 struct APPINFO
*pAppInfo
;
1992 // If we just uninstalled the last AFS app, then do some cleanup.
1993 if (IsAppInstalled(&appServer
) || IsAppInstalled(&appClient
) ||
1994 IsAppInstalled(&appControlCenter
) || IsAppInstalled(&appLightClient
) ||
1995 IsAppInstalled(&appDocs
))
2000 bSilentMode
= !IsWindowVisible(hIS
);
2002 // Which app did we just uninstall?
2003 pAppInfo
= GetApp();
2005 ShowError(IDS_CANT_DETERMINE_PRODUCT
, 0);
2009 // Get the app's install dir
2010 pszInstallDir
= GetAppInstallDir(pAppInfo
, TRUE
);
2014 // Remove the reg key we used to remember the app install dir
2015 RegDeleteEntryAlt(UNINSTALL_TEMP_INFO_KEY
, REGENTRY_KEY
);
2017 // Try to remove the reg key used to store config info, but only
2018 // if there are no app config info sub keys present.
2019 if (!DoSubKeysExist(AFS_PRESERVED_CFG_INFO_KEY
))
2020 RegDeleteEntryAlt(AFS_PRESERVED_CFG_INFO_KEY
, REGENTRY_KEY
);
2022 // Remove the install dir
2023 RemoveDirectory(pszInstallDir
);
2025 // Attempt to remove the install root and common directories. The are
2026 // shared and so no single app knows to delete them.
2028 // Strip off the app specific part of the install dir
2029 psz
= strrchr(pszInstallDir
, '\\');
2033 sprintf(szDirPath
, "%s\\%s", pszInstallDir
, "Common");
2034 RemoveDirectory(szDirPath
);
2036 // Remove the Common directory from the system path
2037 RemoveFromPath(szDirPath
);
2039 // Remove all of the documentation dirs
2040 sprintf(szDirPath
, "%s\\%s", pszInstallDir
, "Documentation");
2041 RemoveDirectoryTree(szDirPath
);
2043 // Ok, up to this point we have been removing files we know we
2044 // created. However, after this point we are into the path
2045 // that the user chose for our install root. The default for
2046 // this is IBM/Afs, but they could have chosen anything,
2047 // including a dir or dirs that have other products in them.
2048 // We will check to see if it is IBM\AFS and if it is then we
2049 // will attempt to remove them.
2051 // Back up a level and look for AFS
2052 psz
= strrchr(pszInstallDir
, '\\');
2054 if (stricmp(psz
+ 1, "AFS") == 0) {
2055 RemoveDirectory(pszInstallDir
);
2060 // Back up a level and look for IBM
2061 psz
= strrchr(pszInstallDir
, '\\');
2063 if (stricmp(psz
+ 1, "IBM") == 0) {
2064 RemoveDirectory(pszInstallDir
);
2069 // Remove the root afs start menu entry
2070 psz
= GetStartMenuRoot();
2073 // Remove everything under our branch
2074 sprintf(szDirPath
, "%s\\IBM WebSphere\\Performance Pack\\AFS", psz
);
2075 RemoveDirectoryTree(szDirPath
);
2077 // Remove the IBM stuff only if the dirs are empty
2078 sprintf(szDirPath
, "%s\\IBM WebSphere\\Performance Pack", psz
);
2079 if (RemoveDirectory(szDirPath
)) {
2080 sprintf(szDirPath
, "%s\\IBM WebSphere", psz
);
2081 RemoveDirectory(szDirPath
);
2084 sprintf(szDirPath
, "%s\\IBM AFS", psz
);
2085 RemoveDirectoryTree(szDirPath
);
2090 BOOLEAN _stdcall
DllEntryPoint(HANDLE dll
, DWORD reason
, PVOID reserved
)
2092 if (reason
== DLL_PROCESS_ATTACH
) {
2093 hinst
= (HINSTANCE
)dll
;
2094 TaLocale_LoadCorrespondingModuleByName (hinst
, "afs_setup_utils.dll");
2100 extern "C" int WINAPI
Test (HINSTANCE hInst
, HINSTANCE hPrev
, LPSTR psz
, int nCmdShow
)
2102 ShowLicense ("TEST", "\\\\fury\\afssetup\\license\\ja_JP.rtf");