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");