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>
34 #include <winnt/osi_malloc.h>
37 #include "progress_dlg.h"
39 #include "forceremove.h"
43 * PROTOTYPES _________________________________________________________________
46 static char *GetAppInstallDir(struct APPINFO *pApp, BOOL bRemembered);
47 BOOL UninstallCredsTool();
48 BOOL ServerSpecificUninstall();
49 BOOL ClientSpecificUninstall();
54 * DEFINITIONS _________________________________________________________________
57 #define SUCALLCONV WINAPI
59 #define UNINSTALL_TEMP_INFO_KEY "HKEY_LOCAL_MACHINE\\Software\\AfsUninstallTempInfo"
60 #define INSTALL_DIR_VALUE_NAME "InstallDir"
62 #define AFS_PRESERVED_CFG_INFO_KEY "HKEY_LOCAL_MACHINE\\Software\\AfsPreservedConfigInfo"
64 #define MS_SHARED_FILES_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs"
66 // Log file to use when running in silent mode
67 #define UNINSTALL_ERROR_LOG_NAME "\\AfsUninstallErrorLog.txt"
68 #define INSTALL_ERROR_LOG_NAME "\\AfsInstallErrorLog.txt"
70 #define TARGETDIR "<TARGETDIR>"
71 #define WINDIR "<WINDIR>"
72 #define WINSYSDIR "<WINSYSDIR>"
74 #define WIN9X_START_MENU_REG_KEY "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
75 #define WIN9X_START_MENU_REG_VALUE "Programs"
77 #define WINNT_START_MENU_REG_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
78 #define WINNT_START_MENU_REG_VALUE "Common Programs"
80 #define LOCALE_ID_LEN 4
88 typedef BOOL (APP_UNINSTALL_FUNC)();
99 char *pszSvcDisplayName;
101 char *pszNetworkProviderOrder;
103 // Message to use to tell the user that we have to stop the service
104 int nServiceShutdownMsgID;
106 // Message to use for the progress dialog that is shown while
107 // waiting for the service to stop.
108 int nServiceShutdownProgressMsgID;
110 // Location in registry of a key we can use to know that the app is installed
113 // Location in registry of this app's install dir
114 struct REGVALUE regInstallDir;
117 char *pszLocalRoot; // The root dir below the install dir
118 char *pszBinPath; // Path to remove from the system path
120 // Generated files and directories to delete. These are both multistring lists.
121 char *pszDirsToDel; // All files in these dirs will be deleted
122 char *pszFilesToDel; // Use this if you want to delete files but leave the dir. Wildcards can be used.
124 // Registry values to remove
125 struct REGVALUE *pRegValues;
126 struct REGVALUE *pWinNTRegValues; // Only remove these if running WinNT
127 struct REGVALUE *pWin9XRegValues; // Only remove these if running Win9X
129 // Start menu entries to delete
130 char *pszStartMenuEntries;
132 // Registry keys to save if a user wants to preserve config info during uninstall
133 char *pszRegKeysToPreserve;
134 int nPreserveConfigInfoMsgID;
136 // Uninstall func - used for things specific to this app
137 APP_UNINSTALL_FUNC *pUninstallFunc;
142 * App info structure for the Server product
144 struct APPINFO appServer = {
150 AFSREG_SVR_SVC_DISPLAYNAME_DATA,
152 0, // No network provider order
154 IDS_MUST_STOP_SERVER,
155 IDS_WAITING_FOR_SERVER_TO_STOP,
157 AFSREG_SVR_SW_VERSION_KEY,
159 { AFSREG_SVR_SW_VERSION_KEY, AFSREG_SVR_SW_VERSION_DIR_VALUE },
165 TARGETDIR"\\Server\\usr\\afs\\bin\\backup\0"
166 TARGETDIR"\\Server\\usr\\afs\\bin\0"
167 TARGETDIR"\\Server\\usr\\afs\\db\0"
168 TARGETDIR"\\Server\\usr\\afs\\logs\0"
169 TARGETDIR"\\Server\\usr\\afs\\etc\0"
170 TARGETDIR"\\Server\\usr\\afs\\local\0"
171 TARGETDIR"\\Server\\usr\\afs\0"
172 TARGETDIR"\\Server\\usr\0",
175 TARGETDIR"\\Common\\*.gid\0"
176 TARGETDIR"\\Common\\*.fts\0",
179 0, // No NT only reg values
180 0, // No 9x only reg values
184 // Config info to preserve
185 AFSREG_SVR_SVC_KEY"\0",
186 IDS_PRESERVE_SERVER_CONFIG_INFO,
188 0 // No special uninstall function
191 // Registry values to remove for the Client
192 struct REGVALUE clientRegValues[] = {
193 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", "{DC515C27-6CAC-11D1-BAE7-00C04FD140D2}" },
194 { 0, 0 } // This indicates there are no more entries
197 struct REGVALUE clientWinNTRegValues[] = {
198 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\File Manager\\AddOns", "AFS Client FME" },
199 { "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", "SMBDeviceEnabled" },
203 struct REGVALUE clientWin9XRegValues[] = {
204 { "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order", "TransarcAFSDaemon" },
209 * App info structure for the Client product
211 struct APPINFO appClient = {
216 "5250435353004E657462696F730000",
217 AFSREG_CLT_SVC_DISPLAYNAME_DATA,
221 IDS_MUST_STOP_CLIENT,
222 IDS_WAITING_FOR_CLIENT_TO_STOP,
224 AFSREG_CLT_SW_VERSION_KEY,
226 { AFSREG_CLT_SW_VERSION_KEY, AFSREG_CLT_SW_VERSION_DIR_VALUE },
235 TARGETDIR"\\Common\\*.gid\0"
236 TARGETDIR"\\Common\\*.fts\0"
237 WINDIR"\\..\\AFSCache\0"
240 WINDIR"\\afsdsbmt.ini\0"
241 WINDIR"\\afsdcell.ini\0"
242 WINDIR"\\afsd_init.log\0",
245 clientWinNTRegValues,
246 clientWin9XRegValues,
248 // Start menu entries to remove
251 // Config info to preserve
252 AFSREG_CLT_SVC_KEY"\0",
253 IDS_PRESERVE_CLIENT_CONFIG_INFO,
255 ClientSpecificUninstall
260 * App info structure for the Light Client product
262 struct APPINFO appLightClient = {
273 // No service shutdown messages
277 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Light Client",
279 { AFSREG_CLT_SW_VERSION_KEY, AFSREG_CLT_SW_VERSION_DIR_VALUE },
288 TARGETDIR"\\Common\\*.gid\0"
289 TARGETDIR"\\Common\\*.fts\0",
292 clientWinNTRegValues,
293 clientWin9XRegValues,
295 // Start menu entries to remove
298 // Config info to preserve
299 AFSREG_CLT_SVC_KEY"\0",
300 IDS_PRESERVE_LIGHT_CLIENT_CONFIG_INFO,
307 * App info structure for the Control Center product
309 struct APPINFO appControlCenter = {
310 "AFS Control Center",
318 // No network provider order
321 // No service shutdown messages
325 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center",
327 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Control Center\\CurrentVersion", "PathName" },
336 TARGETDIR"\\Common\\*.gid\0"
337 TARGETDIR"\\Common\\*.fts\0",
340 0, // No NT only reg values
341 0, // No 9x only reg values
343 // Start menu entries to remove
346 // Config info to preserve
347 AFSREG_CLT_SVC_KEY"\0",
348 IDS_PRESERVE_CC_CONFIG_INFO,
350 0 // No uninstall function
355 * App info structure for the Sys Admin Doc files
357 struct APPINFO appDocs = {
358 "AFS Supplemental Documentation",
366 // No network provider order
369 // No service shutdown messages
373 "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation",
375 { "HKEY_LOCAL_MACHINE\\SOFTWARE\\TransarcCorporation\\AFS Supplemental Documentation\\CurrentVersion", "PathName" },
384 TARGETDIR"\\Common\\*.gid\0"
385 TARGETDIR"\\Common\\*.fts\0",
388 0, // No NT only reg values
389 0, // No 9x only reg values
391 // Start menu entries to remove
392 "Documentation\\AFS for Windows Backup Command Reference.lnk\0Documentation\\AFS Command Reference Manual.lnk\0Documentation\\AFS System Administrator's Guide.lnk\0",
394 0, // No config info to preserve
396 0 // No uninstall function
400 // Shared and in-use files
413 struct FILEINFO fileInfo[] = {
414 { TARGETDIR"\\Common\\afsbosadmin.dll", SERVER | CC },
415 { TARGETDIR"\\Common\\afscfgadmin.dll", SERVER | CC },
416 { TARGETDIR"\\Common\\afsclientadmin.dll", SERVER | CLIENT | LCLIENT | CC },
417 { TARGETDIR"\\Common\\afskasadmin.dll", SERVER | CC },
418 { TARGETDIR"\\Common\\afsptsadmin.dll", SERVER | CC },
419 { TARGETDIR"\\Common\\afsvosadmin.dll", SERVER | CC },
420 { TARGETDIR"\\Common\\afsadminutil.dll", SERVER | CLIENT | LCLIENT | CC },
421 { TARGETDIR"\\Common\\afsrpc.dll", SERVER | CLIENT | LCLIENT | CC },
422 { TARGETDIR"\\Common\\afsauthent.dll", SERVER | CLIENT | LCLIENT | CC },
423 { TARGETDIR"\\Common\\afspthread.dll", SERVER | CLIENT | LCLIENT | CC },
424 { TARGETDIR"\\Common\\TaAfsAppLib.dll", SERVER | CLIENT | LCLIENT | CC },
425 { TARGETDIR"\\Common\\afsprocmgmt.dll", SERVER | CLIENT | LCLIENT },
426 { TARGETDIR"\\Common\\afs_config.exe", CLIENT | LCLIENT| CC },
427 { TARGETDIR"\\Common\\afseventmsg_????.dll", SERVER | CLIENT | LCLIENT | CC },
428 { TARGETDIR"\\Common\\afslegal_????.dll", SERVER | CLIENT | LCLIENT | CC },
429 { TARGETDIR"\\Common\\afsserver_????.dll", SERVER | CLIENT | LCLIENT | CC },
430 { TARGETDIR"\\Common\\afssvrcfg_????.dll", SERVER | CLIENT | LCLIENT | CC },
431 { TARGETDIR"\\Common\\TaAfsAccountManager_????.dll",SERVER | CLIENT | LCLIENT | CC },
432 { TARGETDIR"\\Common\\TaAfsAppLib_????.dll", SERVER | CLIENT | LCLIENT | CC },
433 { TARGETDIR"\\Common\\TaAfsServerManager_????.dll", SERVER | CLIENT | LCLIENT | CC },
434 { TARGETDIR"\\Common\\afscreds_????.dll", SERVER | CLIENT | LCLIENT | CC },
435 { TARGETDIR"\\Common\\afs_config_????.dll", SERVER | CLIENT | LCLIENT | CC },
436 { TARGETDIR"\\Common\\afs_cpa_????.dll", SERVER | CLIENT | LCLIENT | CC },
437 { TARGETDIR"\\Common\\afs_shl_ext_????.dll", SERVER | CLIENT | LCLIENT | CC },
438 { TARGETDIR"\\Common\\afs-nt.hlp", SERVER | CLIENT | LCLIENT | CC },
439 { TARGETDIR"\\Common\\afs-nt.cnt", SERVER | CLIENT | LCLIENT | CC },
440 { TARGETDIR"\\Common\\taafssvrmgr.cnt", SERVER | CLIENT | LCLIENT | CC },
441 { TARGETDIR"\\Common\\taafssvrmgr.hlp", SERVER | CLIENT | LCLIENT | CC },
442 { TARGETDIR"\\Common\\taafsusrmgr.cnt", SERVER | CLIENT | LCLIENT | CC },
443 { TARGETDIR"\\Common\\taafsusrmgr.hlp", SERVER | CLIENT | LCLIENT | CC },
444 { TARGETDIR"\\Common\\afs-cc.cnt", SERVER | CLIENT | LCLIENT | CC },
445 { TARGETDIR"\\Common\\afs-cc.hlp", SERVER | CLIENT | LCLIENT | CC },
446 { TARGETDIR"\\Common\\afs-light.cnt", SERVER | CLIENT | LCLIENT | CC },
447 { TARGETDIR"\\Common\\afs-light.hlp", SERVER | CLIENT | LCLIENT | CC },
448 { TARGETDIR"\\Common\\taafscfg.cnt", SERVER | CLIENT | LCLIENT | CC },
449 { TARGETDIR"\\Common\\taafscfg.hlp", SERVER | CLIENT | LCLIENT | CC },
450 { TARGETDIR"\\Client\\PROGRAM\\afs_shl_ext.dll", CLIENT | LCLIENT },
451 { TARGETDIR"\\Client\\PROGRAM\\libafsconf.dll", CLIENT | LCLIENT },
452 { TARGETDIR"\\Client\\PROGRAM\\afslogon.dll", CLIENT },
453 { TARGETDIR"\\Client\\PROGRAM\\afslog95.dll", LCLIENT },
454 { TARGETDIR"\\Control Center\\TaAfsAdmSvr.exe", CC },
455 { WINSYSDIR"\\afs_cpa.cpl", CLIENT | LCLIENT | CC },
456 { WINSYSDIR"\\afsserver.cpl", SERVER },
457 { TARGETDIR"\\Common\\afsdcell.ini", CLIENT | LCLIENT | CC },
458 { TARGETDIR"\\Documentation\\Html\\banner.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
459 { TARGETDIR"\\Documentation\\Html\\books.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
460 { TARGETDIR"\\Documentation\\Html\\bot.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
461 { TARGETDIR"\\Documentation\\Html\\index.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
462 { TARGETDIR"\\Documentation\\Html\\index.htm", SERVER | CLIENT | LCLIENT | CC | DOCS },
463 { TARGETDIR"\\Documentation\\Html\\next.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
464 { TARGETDIR"\\Documentation\\Html\\prev.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
465 { TARGETDIR"\\Documentation\\Html\\toc.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
466 { TARGETDIR"\\Documentation\\Html\\top.gif", SERVER | CLIENT | LCLIENT | CC | DOCS },
467 { TARGETDIR"\\Documentation\\Html\\ReleaseNotes\\relnotes.htm",
468 SERVER | CLIENT | LCLIENT | CC },
469 { TARGETDIR"\\Documentation\\Html\\InstallGd\\afsnt35i.htm",
470 SERVER | CLIENT | LCLIENT | CC },
471 { 0, 0 } // End of list
476 * VARIABLES _________________________________________________________________
482 static BOOL bPreserveConfigInfo;
483 static BOOL bSilentMode;
484 static char *pszInstallDir;
488 * FUNCTIONS _________________________________________________________________
492 static BOOL UpgradeClientIntParm(HKEY hKey, char *pszOldParm, char *pszNewParm)
495 LONG result = ERROR_SUCCESS;
497 nData = GetPrivateProfileInt("AFS Client", pszOldParm, -1, "afsd.ini");
499 result = RegSetValueEx(hKey, pszNewParm, 0, REG_DWORD, (BYTE *)&nData, sizeof(nData));
501 return (result == ERROR_SUCCESS);
504 static BOOL UpgradeClientStringParm(HKEY hKey, char *pszOldParm, char *pszNewParm)
507 LONG result = ERROR_SUCCESS;
509 GetPrivateProfileString("AFS Client", pszOldParm, "", szData, sizeof(szData), "afsd.ini");
511 result = RegSetValueEx(hKey, pszNewParm, 0, REG_SZ, (PBYTE)szData, strlen(szData) + 1);
513 return (result == ERROR_SUCCESS);
516 int SUCALLCONV Upgrade34ClientConfigInfo()
522 result = RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_CLT_SVC_PARAM_KEY, KEY_WRITE, TRUE, &hKey, 0);
523 if (result != ERROR_SUCCESS)
526 UpgradeClientIntParm(hKey, "CacheSize", "CacheSize");
527 UpgradeClientIntParm(hKey, "Stats", "Stats");
528 UpgradeClientIntParm(hKey, "LogoffTokenTransfer", "LogoffTokenTransfer");
529 UpgradeClientIntParm(hKey, "LogoffTokenTransferTimeout", "LogoffTokenTransferTimeout");
530 UpgradeClientIntParm(hKey, "TrapOnPanic", "TrapOnPanic");
531 UpgradeClientIntParm(hKey, "TraceBufferSize", "TraceBufferSize");
532 UpgradeClientIntParm(hKey, "TraceOnShutdown", "TraceOnShutdown");
533 UpgradeClientIntParm(hKey, "ReportSessionStartups", "ReportSessionStartups");
535 UpgradeClientStringParm(hKey, "MountRoot", "MountRoot");
536 UpgradeClientStringParm(hKey, "Cell", "Cell");
538 /* BlockSize to ChunkSize requires convertion */
539 nData = GetPrivateProfileInt("AFS Client", "BlockSize", -1, "afsd.ini");
542 for (chunkSize = 0; (1 << chunkSize) < nData; chunkSize++);
543 (void) RegSetValueEx(hKey, "ChunkSize", 0, REG_DWORD, (BYTE *)&chunkSize, sizeof(chunkSize));
551 int SUCALLCONV Eradicate34Client()
553 if (Client34Eradicate(TRUE) != ERROR_SUCCESS)
559 // This function was written a long time ago by Mike Comer for use by the
560 // original DFS Client for NT install program.
561 int SUCALLCONV CheckIfAdmin(void)
563 HANDLE token = INVALID_HANDLE_VALUE;
567 TOKEN_PRIMARY_GROUP *pgroup;
568 TOKEN_GROUPS *groups;
572 PSID AdministratorSID = NULL;
573 SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
575 // allocate the SID for the Administrators group
576 if (!AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorSID)) {
577 status = GetLastError();
581 // open the process token
582 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token)) {
583 status = GetLastError();
584 token = INVALID_HANDLE_VALUE;
588 // check primary group first
589 buffer = GlobalAlloc(GMEM_FIXED, sizeof(TOKEN_PRIMARY_GROUP));
594 bufLength = sizeof(TOKEN_PRIMARY_GROUP);
596 if (!GetTokenInformation(token, TokenPrimaryGroup, buffer, bufLength, &realBufLength)) {
597 if (realBufLength > bufLength) {
600 bufLength = realBufLength;
601 buffer = GlobalAlloc(GMEM_FIXED, realBufLength);
613 pgroup = (TOKEN_PRIMARY_GROUP *)buffer;
614 if (EqualSid(pgroup->PrimaryGroup, AdministratorSID)) {
617 // okay, try the secondary groups
619 if (!GetTokenInformation(token, TokenGroups, buffer, bufLength, &realBufLength)) {
620 if (realBufLength > bufLength) {
623 bufLength = realBufLength;
624 buffer = GlobalAlloc(GMEM_FIXED, realBufLength);
637 // we have the list of groups here. Process them:
638 groups = (TOKEN_GROUPS *)buffer;
639 for(groupCount = 0; groupCount < groups->GroupCount; groupCount++) {
640 if (EqualSid(groups->Groups[groupCount].Sid, AdministratorSID)) {
649 if (token != INVALID_HANDLE_VALUE) {
657 if (AdministratorSID) {
658 FreeSid(AdministratorSID);
664 static void SetSharedFileRefCount(char *pszFile, int nRefCount)
669 result = RegOpenKeyAlt(AFSREG_NULL_KEY, MS_SHARED_FILES_KEY, KEY_WRITE, FALSE, &hKey, 0);
670 if (result != ERROR_SUCCESS)
674 RegDeleteValue(hKey, pszFile);
676 RegSetValueEx(hKey, pszFile, 0, REG_DWORD, (BYTE *)&nRefCount, sizeof(int));
681 static char *GetTimeStamp()
683 char szTime[64], szDate[64];
684 static char szTimeDate[128];
689 sprintf(szTimeDate, "[%s %s] ", szTime, szDate);
694 int SUCALLCONV WriteToInstallErrorLog(char *pszMsg)
696 static BOOL bWritten = FALSE;
699 // On the first write, recreate the file
700 fp = fopen(INSTALL_ERROR_LOG_NAME, bWritten ? "a" : "w");
704 fprintf(fp, "%s%s\r\n", GetTimeStamp(), pszMsg);
713 static void WriteToUninstallErrorLog(char *pszMsg)
715 static BOOL bWritten = FALSE;
718 // On the first write, recreate the file
719 fp = fopen(UNINSTALL_ERROR_LOG_NAME, bWritten ? "a" : "w");
723 fprintf(fp, "%s%s\r\n", GetTimeStamp(), pszMsg);
730 static char *LoadResString(UINT uID)
732 static char str[256];
733 GetString (str, uID);
737 static void ShowError(UINT nResID, LONG nError)
745 psz = LoadResString(nResID);
749 sprintf(szErr, "unknown error msg (Msg ID = %d)", nResID);
751 psz = LoadResString(IDS_INSTALLATION_FAILURE);
752 strcpy(szPrompt, psz ? psz : "An error has occurred: %s (Last Error = %ld).");
754 sprintf(szMsg, szPrompt, szErr, nError);
756 psz = LoadResString(IDS_TITLE);
757 strcpy(szTitle, psz ? psz : "AFS");
760 WriteToUninstallErrorLog(szMsg);
762 MessageBox(hDlg, szMsg, szTitle, MB_OK);
765 static int ShowMsg(UINT nResID, int nType)
770 psz = LoadResString(IDS_TITLE);
771 strcpy(szTitle, psz ? psz : "AFS");
773 return MessageBox(hDlg, LoadResString(nResID), szTitle, nType);
776 static char *GetAppInstallDir(struct APPINFO *pApp, BOOL bRemembered)
781 static char szInstallDir[256];
786 pszKey = bRemembered ? UNINSTALL_TEMP_INFO_KEY : pApp->regInstallDir.pszKey;
787 pszValue = bRemembered ? INSTALL_DIR_VALUE_NAME : pApp->regInstallDir.pszValue;
789 dwSize = sizeof(szInstallDir);
791 nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);
792 if (nResult == ERROR_SUCCESS) {
793 nResult = RegQueryValueEx(hKey, pszValue, 0, &dwType, (PBYTE)szInstallDir, &dwSize);
797 if (nResult != ERROR_SUCCESS) {
798 ShowError(IDS_CANT_DETERMINE_APP_PATH, nResult);
802 FilepathNormalizeEx(szInstallDir, FPN_BACK_SLASHES);
807 static BOOL DoesRegKeyExist(char *pszKey)
812 nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);
813 if (nResult == ERROR_SUCCESS) {
821 static BOOL IsAppInstalled(struct APPINFO *pApp)
823 return DoesRegKeyExist(pApp->pszAppKey);
826 static void BuildShortPath(char *pszShortPath, UINT nShortPathLen, char *pszInstallDir, char *pszPath)
828 strncpy(pszShortPath, pszInstallDir, nShortPathLen);
829 strncat(pszShortPath, pszPath, nShortPathLen);
831 GetShortPathName(pszShortPath, pszShortPath, nShortPathLen);
834 static BOOL IsWin95()
836 OSVERSIONINFO versionInformation;
838 versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
840 GetVersionEx(&versionInformation);
842 if ((versionInformation.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
843 (versionInformation.dwMinorVersion == 0))
851 OSVERSIONINFO versionInformation;
853 versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
855 GetVersionEx(&versionInformation);
857 if ((versionInformation.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
858 (versionInformation.dwMinorVersion == 10))
864 static BOOL IsServiceInstalled(char *pszServiceKey)
868 if (RegOpenKeyAlt(0, pszServiceKey, KEY_READ, FALSE, &hKey, 0) == ERROR_SUCCESS) {
876 // If this fails in anyway we just return. No error is displayed.
877 static void MakeSureServiceDoesNotExist(char *pszName)
879 SC_HANDLE hServer = 0, hSCM = 0;
880 SERVICE_STATUS status;
882 hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
884 hServer = OpenService(hSCM, pszName, SERVICE_ALL_ACCESS | DELETE);
886 if (QueryServiceStatus(hServer, &status)) {
887 if (status.dwCurrentState != SERVICE_STOPPED) {
888 if (!ControlService(hServer, SERVICE_CONTROL_STOP, &status)) {
889 CloseServiceHandle(hServer);
890 CloseServiceHandle(hSCM);
896 // Try to delete even if status query fails
897 DeleteService(hServer);
902 CloseServiceHandle(hServer);
904 CloseServiceHandle(hSCM);
907 static int InstallService(char *pszName, char *pszDependOn, char *pszDisplayName, char *pszServicePath, BOOL bInteractive)
909 SC_HANDLE hServer = 0, hSCM;
910 BOOL bRestoreOldConfig = FALSE;
912 if (!AddToProviderOrder(AFSREG_CLT_SVC_NAME)) {
913 ShowError(ERROR_FILE_NOT_FOUND, GetLastError());
916 hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
918 ShowError(IDS_SCM_OPEN_FAILED, GetLastError());
922 /* This code is not used, but it could be handy in the future so I am keeping it here.
924 // If the service exists, then we (most probably) are in the middle of an upgrade or reinstall.
925 bRestoreOldConfig = IsServiceInstalled(pszName);
927 if (bRestoreOldConfig) {
928 hServer = OpenService(hSCM, pszName, SERVICE_ALL_ACCESS);
929 if (!hServer || !ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
930 ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED, GetLastError());
931 bRestoreOldConfig = FALSE;
932 // Fall through to service creation below
937 if (!bRestoreOldConfig) {
940 // If the service already exists, the create call will fail. This can
941 // happen if uninstall failed (which is not infrequent). Making sure the
942 // service does not exist makes it easier for a user to install over top of
943 // a previously failed uninstall.
944 MakeSureServiceDoesNotExist(pszName);
946 dwServiceType = SERVICE_WIN32_OWN_PROCESS;
948 dwServiceType |= SERVICE_INTERACTIVE_PROCESS;
950 hServer = CreateService(hSCM, pszName, pszDisplayName,
951 SERVICE_ALL_ACCESS, dwServiceType, SERVICE_AUTO_START,
952 SERVICE_ERROR_NORMAL, pszServicePath, 0, 0, "RPCSS\0Netbios\0\0", 0, 0);
955 ShowError(IDS_SERVICE_CREATE_FAILED, GetLastError());
959 CloseServiceHandle(hServer);
961 CloseServiceHandle(hSCM);
966 int SUCALLCONV InstallServerService(char *pszServicePath)
968 return InstallService(appServer.pszSvcName, 0, appServer.pszSvcDisplayName, pszServicePath, TRUE);
971 int SUCALLCONV InstallClientService(char *pszServicePath)
973 return InstallService(appClient.pszSvcName, appClient.pszSvcDependOn, appClient.pszSvcDisplayName, pszServicePath, FALSE);
976 static int UninstallService(struct APPINFO *pAppInfo)
978 SC_HANDLE hServer, hSCM;
979 SERVICE_STATUS status;
981 BOOL bServer = FALSE;
982 BOOL bShowingProgressDlg = FALSE;
984 if (!RemoveFromProviderOrder(AFSREG_CLT_SVC_NAME)) {
985 ShowError(ERROR_FILE_NOT_FOUND, GetLastError());
988 hSCM = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
990 ShowError(IDS_SCM_OPEN_FAILED, GetLastError());
994 hServer = OpenService(hSCM, pAppInfo->pszSvcName, SERVICE_ALL_ACCESS | DELETE);
996 ShowError(IDS_SERVICE_OPEN_FAILED, GetLastError());
997 CloseServiceHandle(hSCM);
1001 if (!QueryServiceStatus(hServer, &status)) {
1002 ShowError(IDS_SERVICE_QUERY_FAILED, GetLastError());
1003 CloseServiceHandle(hServer);
1004 CloseServiceHandle(hSCM);
1008 if (status.dwCurrentState != SERVICE_STOPPED) {
1009 if (pAppInfo->nServiceShutdownMsgID) {
1010 if (!bSilentMode && (ShowMsg(pAppInfo->nServiceShutdownMsgID, MB_YESNO | MB_ICONQUESTION) == IDNO)) {
1011 CloseServiceHandle(hServer);
1012 CloseServiceHandle(hSCM);
1018 bShowingProgressDlg = ShowProgressDialog(LoadResString(pAppInfo->nServiceShutdownProgressMsgID));
1020 if (!ControlService(hServer, SERVICE_CONTROL_STOP, &status)) {
1021 if (bShowingProgressDlg)
1022 HideProgressDialog();
1023 ShowError(IDS_SERVICE_STOP_FAILED, GetLastError());
1024 CloseServiceHandle(hServer);
1025 CloseServiceHandle(hSCM);
1030 // Wait for the service to stop
1031 while (status.dwCurrentState != SERVICE_STOPPED) {
1032 // I stopped waiting on dwWaitHint because it seemed the wait hint was too long.
1033 // The service would be stopped but we'd still be asleep for a long time yet.
1034 Sleep(5000); //status.dwWaitHint);
1036 if (!QueryServiceStatus(hServer, &status)) {
1037 if (bShowingProgressDlg)
1038 HideProgressDialog();
1039 ShowError(IDS_SERVICE_QUERY_FAILED, GetLastError());
1040 CloseServiceHandle(hServer);
1041 CloseServiceHandle(hSCM);
1046 // The service has been stopped
1047 if (bShowingProgressDlg)
1048 HideProgressDialog();
1050 // This code to disable the service may be of use some day so I am keeping it here.
1051 // bOk = ChangeServiceConfig(hServer, SERVICE_NO_CHANGE, SERVICE_DISABLED, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0);
1053 bOk = DeleteService(hServer);
1056 ShowError(IDS_SERVICE_DELETE_FAILED, GetLastError());
1058 CloseServiceHandle(hServer);
1059 CloseServiceHandle(hSCM);
1061 return (bOk ? 0 : -1);
1064 int SUCALLCONV AddToNetworkProviderOrder(char *pszWhatToAdd)
1066 return AddToProviderOrder(pszWhatToAdd) ? 0 : -1;
1069 static int RemoveFromNetworkProviderOrder(char *pszWhatToDel)
1071 return RemoveFromProviderOrder(pszWhatToDel) ? 0 : -1;
1074 int SUCALLCONV AddToPath(char *pszPath)
1076 return AddToSystemPath(pszPath) ? 0 : -1;
1079 static int RemoveFromPath(char *pszPath)
1081 return RemoveFromSystemPath(pszPath) ? 0 : -1;
1084 static void RemoveFiles(char *pszFileSpec)
1086 struct _finddata_t fileinfo;
1088 char szDel[MAX_PATH];
1089 char szDir[MAX_PATH];
1092 strcpy(szDir, pszFileSpec);
1093 p = strrchr(szDir, '\\');
1097 hSearch = _findfirst(pszFileSpec, &fileinfo);
1102 if ((strcmp(fileinfo.name, ".") != 0) && (strcmp(fileinfo.name, "..") != 0)) {
1103 sprintf(szDel, "%s\\%s", szDir, fileinfo.name);
1107 if (_findnext(hSearch, &fileinfo) == -1)
1111 _findclose(hSearch);
1114 static void RemoveDir(char *pszDir)
1116 char szFileSpec[MAX_PATH];
1118 sprintf(szFileSpec, "%s\\*.*", pszDir);
1120 RemoveFiles(szFileSpec);
1121 RemoveDirectory(pszDir);
1124 static void RemoveRegValues(struct REGVALUE *pRegValues)
1126 struct REGVALUE *pCurValue;
1133 for (pCurValue = pRegValues; pCurValue->pszKey; pCurValue++) {
1134 nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pCurValue->pszKey, KEY_ALL_ACCESS, FALSE, &hKey, 0);
1136 if (nResult == ERROR_SUCCESS) {
1137 nResult = RegDeleteValue(hKey, pCurValue->pszValue);
1141 if (nResult != ERROR_SUCCESS)
1142 ShowError(IDS_REG_DELETE_VALUE_ERROR, nResult);
1146 static BOOL UninstallCredsTool()
1148 int nResult = WinExec("afscreds /uninstall", SW_HIDE);
1150 if (nResult <= 31) {
1151 if (nResult != ERROR_FILE_NOT_FOUND)
1152 ShowError(IDS_CANT_UNINSTALL_AFSCREDS, nResult);
1155 // Always return true. We don't want the uninstall to completely fail just
1156 // because the creds tool didn't uninstall.
1161 static char *GetTempDir()
1164 static char szTempDir[MAX_PATH];
1166 result = GetTempPath(sizeof(szTempDir) - 1, szTempDir);
1173 static char *GetRootInstallDir()
1176 static char szRootInstallDir[MAX_PATH] = "";
1178 if (szRootInstallDir[0] == 0) {
1179 strcpy(szRootInstallDir, pszInstallDir);
1181 // Strip off the app specific part of the install dir
1182 psz = strrchr(szRootInstallDir, '\\');
1187 return szRootInstallDir;
1190 static BOOL ClientSpecificUninstall()
1194 // This function needs to do two things. First it needs to see if the server is
1195 // installed, and if it is, ask the user if they really want to uninstall the
1196 // client given that the server needs the client. Second, if we are uninstalling
1197 // the client, we need to uninstall the creds tool.
1200 if (IsAppInstalled(&appServer)) {
1201 nChoice = ShowMsg(IDS_CLIENT_NEEDED_BY_SERVER, MB_ICONQUESTION | MB_YESNO);
1202 if (nChoice == IDNO)
1203 return FALSE; // Cancel the uninstall
1207 UninstallCredsTool();
1212 static struct APPINFO *GetApp()
1214 #ifdef SERVER_UNINST
1219 return &appControlCenter;
1220 #elif LIGHT_CLIENT_UNINST
1221 return &appLightClient;
1229 static void RememberInstallDir(char *pszInstallDir)
1233 // We remember the install dir so that when the UninstUninitialize function is called
1234 // by the InstallShield uninstaller, we can find out where we were installed to. We
1235 // have to do this because by the time that function is called, the registry values
1236 // created at install time are already gone. We need to be able to find out where we
1237 // were installed so we can clean up anything IS couldn't uninstall. If this fails in
1238 // any way then we don't care. The only consequence is that some junk might be left on
1239 // the users' system after an uninstall.
1241 LONG result = RegOpenKeyAlt(AFSREG_NULL_KEY, UNINSTALL_TEMP_INFO_KEY, KEY_WRITE, TRUE, &hKey, 0);
1242 if (result != ERROR_SUCCESS)
1245 RegSetValueEx(hKey, INSTALL_DIR_VALUE_NAME, 0, REG_SZ, (PBYTE)pszInstallDir, strlen(pszInstallDir) + 1);
1250 int SUCALLCONV SetSilentMode()
1257 static char *GetWinDir()
1259 static char szWinDir[MAX_PATH] = "";
1262 GetWindowsDirectory(szWinDir, sizeof(szWinDir));
1267 static char *GetWinSysDir()
1269 static char szWinSysDir[MAX_PATH] = "";
1271 if (!szWinSysDir[0])
1272 GetSystemDirectory(szWinSysDir, sizeof(szWinSysDir));
1277 static char *GetLocaleID()
1279 static char szID[25] = "";
1282 LCID dwID = GetSystemDefaultLCID();
1284 // Nuke the high word. It contains a sort ID.
1287 // Convert locale ID to a string
1288 itoa(dwID, szID, 10);
1290 // This thing should never be more than LOCALE_ID_LEN characters long.
1291 szID[LOCALE_ID_LEN] = 0;
1297 static char *ExpandPath(char *pszFile)
1299 static char szPath[MAX_PATH];
1304 // Convert a path containing TARGETDIR, WINDIR, or WINSYSDIR to a
1305 // real path in the file system. One of these MUST be the start of
1306 // the file path passed in. Also convert the string ???? to an
1307 // actual locale number.
1308 if (strncmp(pszFile, TARGETDIR, strlen(TARGETDIR)) == 0)
1309 strcpy(szPath, GetRootInstallDir());
1310 else if (strncmp(pszFile, WINDIR, strlen(WINDIR)) == 0)
1311 strcpy(szPath, GetWinDir());
1312 else if (strncmp(pszFile, WINSYSDIR, strlen(WINSYSDIR)) == 0)
1313 strcpy(szPath, GetWinSysDir());
1316 psz = strchr(pszFile, '\\');
1318 strcat(szPath, psz);
1320 strcpy(szPath, pszFile);
1322 // Is this a language dll?
1323 psz = strstr(szPath, "????.");
1325 // If it is, replace ???? with the locale number
1327 strncpy(psz, GetLocaleID(), LOCALE_ID_LEN);
1332 static BOOL FileNeededByOtherApp(struct APPINFO *pApp, struct FILEINFO *pFileInfo)
1334 // If the file is used by the server, the app being uninstalled is not the server, and
1335 // the server is installed, then this file is used by another app.
1337 if ((pFileInfo->nUsedBy & LCLIENT) && (pApp != &appLightClient) && IsAppInstalled(&appLightClient))
1342 if ((pFileInfo->nUsedBy & SERVER) && (pApp != &appServer) && IsAppInstalled(&appServer))
1345 if ((pFileInfo->nUsedBy & CLIENT) && (pApp != &appClient) && IsAppInstalled(&appClient))
1348 if ((pFileInfo->nUsedBy & CC) && (pApp != &appControlCenter) && IsAppInstalled(&appControlCenter))
1354 static void DeleteInUseFiles(struct APPINFO *pAppInfo, struct FILEINFO *pFileInfo)
1356 char szSrcPath[MAX_PATH];
1357 char szDestPath[MAX_PATH];
1358 char szTempDir[MAX_PATH];
1361 // If some app's file has been loaded before the app is uninstalled, then
1362 // when an uninstall is attempted, the application and all of the dlls that
1363 // its uses will be in use and IS will not be able to delete them. Normally this
1364 // is not a problem because IS will tell the user to reboot to finish the uninstall.
1365 // However, we must support the ability to perform a silent uninstall followed
1366 // immediatly by an install of the same product to the same directories. If we let
1367 // IS handle the uninstall of these files, this is not possible. The reason is that
1368 // when IS fails to remove these in use files, it marks them for deletion after the
1369 // next reboot, which is fine. Unfortunately, it leaves them in the dirs they were
1370 // installed to. So if we don't immediately reboot and perform an install to the
1371 // same dirs, once a reboot is performed, those files get deleted and we have a
1372 // broken installation.
1374 // What we will do to fix all of this, is when the client is uninstalled, but
1375 // before IS does anything, we will move the in use files and associated dlls
1376 // into the temp dir and mark them for delete after a reboot. Then an install
1377 // that follows will succeed.
1379 // Delete the files that may be in use. If they are we actually move
1380 // them to the temp dir and mark them for deletion after the next reboot.
1381 for (ii = 0; pFileInfo[ii].pszName != 0; ii++) {
1382 // Get the source path
1383 strcpy(szSrcPath, ExpandPath(pFileInfo[ii].pszName));
1385 // Only delete the file if it is not used by some other app
1386 if (FileNeededByOtherApp(pAppInfo, &pFileInfo[ii]))
1389 // If the file doesn't exist then go on to the next file.
1390 if (_access(szSrcPath, 0) != 0)
1393 // See if we can do a regular delete of the file
1394 if (DeleteFile(szSrcPath)) {
1395 SetSharedFileRefCount(szSrcPath, 0);
1399 // Get a temp dir that is on the same drive as the src path.
1400 // We can't move an in use file to a different drive.
1401 strcpy(szTempDir, GetTempDir());
1402 if (szTempDir[0] != szSrcPath[0]) {
1403 // Get the drive, colon, and slash of the src path
1404 strncpy(szTempDir, szSrcPath, 3);
1408 // Get the dest path - we will rename the file during the move
1409 GetTempFileName(szTempDir, "AFS", 0, szDestPath);
1411 // Move from source to dest, marking the file for deletion after a reboot
1413 if (MoveFile(szSrcPath, szDestPath)) {
1414 WritePrivateProfileString("rename", szSrcPath, szDestPath, "wininit.ini");
1415 SetSharedFileRefCount(szSrcPath, 0);
1417 } else { // WinNT or Win98
1418 if (MoveFileEx(szSrcPath, szDestPath, MOVEFILE_REPLACE_EXISTING)) {
1419 SetFileAttributes(szDestPath, FILE_ATTRIBUTE_NORMAL);
1420 MoveFileEx(szDestPath, 0, MOVEFILE_DELAY_UNTIL_REBOOT);
1421 SetSharedFileRefCount(szSrcPath, 0);
1427 // Delete a directory and all its files and subdirectories - Yee haaa!
1428 static void RemoveDirectoryTree(char *pszDir)
1431 WIN32_FIND_DATA findFileData;
1432 char szSpec[MAX_PATH];
1433 char szSubFileOrDir[MAX_PATH];
1436 sprintf(szSpec, "%s\\*.*", pszDir);
1438 // First delete the contents of the dir
1439 hFind = FindFirstFile(szSpec, &findFileData);
1440 bContinue = (hFind != INVALID_HANDLE_VALUE);
1443 if ((strcmp(findFileData.cFileName, ".") != 0) && (strcmp(findFileData.cFileName, "..") != 0)) {
1444 sprintf(szSubFileOrDir, "%s\\%s", pszDir, findFileData.cFileName);
1446 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1447 RemoveDirectoryTree(szSubFileOrDir);
1449 DeleteFile(szSubFileOrDir);
1452 bContinue = FindNextFile(hFind, &findFileData);
1457 // Now remove the dir
1458 RemoveDirectory(pszDir);
1461 static char *GetStartMenuRoot()
1470 static char szStartMenuRoot[MAX_PATH] = "";
1472 if (szStartMenuRoot[0] == 0) {
1473 dwSize = sizeof(szStartMenuRoot);
1476 pszKey = WINNT_START_MENU_REG_KEY;
1477 pszValue = WINNT_START_MENU_REG_VALUE;
1479 pszKey = WIN9X_START_MENU_REG_KEY;
1480 pszValue = WIN9X_START_MENU_REG_VALUE;
1483 nResult = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);
1484 if (nResult == ERROR_SUCCESS) {
1485 nResult = RegQueryValueEx(hKey, pszValue, 0, &dwType, (PBYTE)szStartMenuRoot, &dwSize);
1489 if (nResult != ERROR_SUCCESS)
1493 FilepathNormalizeEx(szStartMenuRoot, FPN_BACK_SLASHES);
1495 return szStartMenuRoot;
1498 static char *GetAfsStartMenuRoot()
1500 static char szAfsStartMenuRoot[MAX_PATH] = "";
1501 char *pszStartMenuRoot;
1503 if (szAfsStartMenuRoot[0] == 0) {
1504 pszStartMenuRoot = GetStartMenuRoot();
1505 if (!pszStartMenuRoot)
1509 sprintf(szAfsStartMenuRoot, "%s\\IBM WebSphere\\Performance Pack\\AFS", pszStartMenuRoot );
1511 sprintf(szAfsStartMenuRoot, "%s\\IBM AFS", pszStartMenuRoot );
1514 return szAfsStartMenuRoot;
1517 static BOOL IsADir(char *pszName)
1519 struct _stat statbuf;
1521 if (_stat(pszName, &statbuf) < 0)
1524 return statbuf.st_mode & _S_IFDIR;
1527 static void DeleteStartMenuEntries(char *pszEntries)
1529 char szStartMenuPath[MAX_PATH];
1530 char *pszAfsStartMenuRoot;
1533 pszAfsStartMenuRoot = GetAfsStartMenuRoot();
1535 if (!pszAfsStartMenuRoot)
1538 for (pszCurEntry = pszEntries; *pszCurEntry; pszCurEntry += strlen(pszCurEntry) + 1) {
1539 sprintf(szStartMenuPath, "%s\\%s", pszAfsStartMenuRoot, pszCurEntry);
1540 if (IsADir(szStartMenuPath))
1541 RemoveDirectoryTree(szStartMenuPath);
1543 DeleteFile(szStartMenuPath);
1547 static void RefreshStartMenu()
1549 char *pszAfsStartMenuRoot;
1550 char szTemp[MAX_PATH];
1552 pszAfsStartMenuRoot = GetAfsStartMenuRoot();
1553 if (!pszAfsStartMenuRoot)
1556 sprintf(szTemp, "%s - Refresh Attempt", pszAfsStartMenuRoot);
1558 // Deleting items from below the root level of the start menu does not
1559 // cause it to refresh. In order that users can see changes without
1560 // rebooting we will temporarily rename our root most entry, which
1561 // does cause a refresh of the start menu.
1562 MoveFileEx(pszAfsStartMenuRoot, szTemp, MOVEFILE_REPLACE_EXISTING);
1563 MoveFileEx(szTemp, pszAfsStartMenuRoot, MOVEFILE_REPLACE_EXISTING);
1566 static BOOL PreserveConfigInfo(struct APPINFO *pApp)
1569 char szDestKey[256];
1572 bPreserveConfigInfo = TRUE;
1574 // If not in silent mode, ask user if they want to preserve the cfg info
1576 int nChoice = ShowMsg(pApp->nPreserveConfigInfoMsgID, MB_ICONQUESTION | MB_YESNOCANCEL);
1577 if (nChoice == IDCANCEL)
1578 return FALSE; // Cancel the uninstall
1579 else if (nChoice == IDNO) {
1580 bPreserveConfigInfo = FALSE; // User doesn't want to preserve the config info
1585 // Copy each reg key (and all of its subkeys and values) to another place in the registry.
1586 for (pszRegKey = pApp->pszRegKeysToPreserve; *pszRegKey; pszRegKey += strlen(pszRegKey) + 1) {
1587 if (!DoesRegKeyExist(pszRegKey))
1590 // Create the destination path for the copy
1591 sprintf(szDestKey, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName, pszRegKey);
1594 result = RegDupKeyAlt(pszRegKey, szDestKey);
1596 if ((result != ERROR_SUCCESS) && (result != ERROR_FILE_NOT_FOUND)) {
1597 // If the copy failed, then delete any copies that succeeded
1598 sprintf(szDestKey, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);
1599 RegDeleteEntryAlt(szDestKey, REGENTRY_KEY);
1604 // Remember the integrated login setting if this app supports that and it was turned on
1605 if (pApp->pszNetworkProviderOrder) {
1606 // Was integerated login turned on?
1608 bOk = InNetworkProviderOrder(pApp->pszNetworkProviderOrder, &bOn);
1611 sprintf(szDestKey, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);
1612 result = RegOpenKeyAlt(AFSREG_NULL_KEY, szDestKey, KEY_WRITE, TRUE, &hKey, 0);
1613 // The existance of the key is a flag indicating that integrated login was turned on
1619 if ((result == ERROR_SUCCESS) || bSilentMode)
1620 return TRUE; // Continue with uninstall
1622 // Report the error and ask the user if they want to continue the uninstall
1623 return (ShowMsg(IDS_SAVE_OF_CONFIG_INFO_FAILED, MB_ICONEXCLAMATION | MB_YESNO) == IDYES);
1626 int SUCALLCONV RestoreConfigInfo(int nApp)
1630 struct APPINFO *pApp = 0;
1631 BOOL bError = FALSE;
1635 case SERVER: pApp = &appServer; break;
1636 case CLIENT: pApp = &appClient; break;
1637 case LCLIENT: pApp = &appLightClient; break;
1638 case CC: pApp = &appControlCenter; break;
1644 // Copy each reg key (and all of its subkeys and values) back to its original place in the registry.
1645 for (pszRegKey = pApp->pszRegKeysToPreserve; *pszRegKey; pszRegKey += strlen(pszRegKey) + 1) {
1646 // Create the source path for the copy
1647 sprintf(szSrcKey, "%s\\%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName, pszRegKey);
1649 if (!DoesRegKeyExist(szSrcKey))
1652 // Try to restore as many of the keys as possible. Report any errors at the end.
1655 result = RegDupKeyAlt(szSrcKey, pszRegKey);
1656 if ((result != ERROR_SUCCESS) && (result != ERROR_FILE_NOT_FOUND))
1660 // Restore integrated login if this app was using it
1661 if (pApp->pszNetworkProviderOrder) {
1662 // Check if integrated login was turned on. The IntegratedLogin key is a flag
1663 // telling us that it was on. If the key does not exist, integrated login was
1665 sprintf(szSrcKey, "%s\\%s\\IntegratedLogin", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);
1666 if (DoesRegKeyExist(szSrcKey)) {
1667 if (!AddToProviderOrder(pApp->pszNetworkProviderOrder))
1672 // Remove our saved copies of the config info
1673 sprintf(szSrcKey, "%s\\%s", AFS_PRESERVED_CFG_INFO_KEY, pApp->pszAppName);
1674 RegDeleteEntryAlt(szSrcKey, REGENTRY_KEY);
1677 ShowError(IDS_RESTORE_OF_PREVIOUS_CONFIG_FAILED, 0);
1682 static BOOL DoSubKeysExist(char *pszKey)
1686 char *pszSubKeys = 0;
1689 result = RegOpenKeyAlt(AFSREG_NULL_KEY, pszKey, KEY_READ, FALSE, &hKey, 0);
1690 if (result != ERROR_SUCCESS)
1693 result = RegEnumKeyAlt(hKey, &pszSubKeys);
1696 if (result != ERROR_SUCCESS)
1709 * The following definitions are taken from richedit.h:
1713 #define EM_SETBKGNDCOLOR (WM_USER + 67) // from Richedit.h
1714 #define EM_STREAMIN (WM_USER + 73) // from Richedit.h
1715 #define SF_RTF 0x0002
1717 typedef DWORD (CALLBACK *EDITSTREAMCALLBACK)(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);
1719 typedef struct _editstream {
1720 DWORD dwCookie; /* user value passed to callback as first parameter */
1721 DWORD dwError; /* last error */
1722 EDITSTREAMCALLBACK pfnCallback;
1729 DWORD CALLBACK License_StreamText (DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
1731 LPTSTR psz = (LPTSTR)dwCookie;
1732 LONG cchAvail = lstrlen(psz);
1733 if ((*pcb = min(cchAvail, cb)) != 0) {
1734 memcpy (pbBuff, psz, *pcb);
1735 memmove (psz, &psz[*pcb], cchAvail - *pcb + 1);
1741 void License_OnInitDialog (HWND hDlg, LPTSTR pszFile)
1743 // Open the license file and shove its text in our RichEdit control
1746 if ((hFile = CreateFile (pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
1749 if ((cbText = GetFileSize (hFile, NULL)) != 0) {
1751 LPTSTR abText = (LPTSTR)GlobalAlloc (GMEM_FIXED, cbText + 3);
1754 if (ReadFile (hFile, abText, cbText, &cbRead, NULL)) {
1755 abText[ cbRead ] = 0;
1758 memset (&Stream, 0x00, sizeof(Stream));
1759 Stream.dwCookie = (DWORD)abText;
1760 Stream.pfnCallback = License_StreamText;
1762 SendDlgItemMessage (hDlg, IDC_TEXT, EM_STREAMIN, SF_RTF, (LPARAM)&Stream);
1765 GlobalFree (abText);
1768 CloseHandle (hFile);
1771 // Make the control's background be gray
1773 SendDlgItemMessage (hDlg, IDC_TEXT, EM_SETBKGNDCOLOR, FALSE, (LPARAM)GetSysColor(COLOR_BTNFACE));
1776 BOOL CALLBACK License_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1780 SetWindowLong (hDlg, DWL_USER, lp);
1781 License_OnInitDialog (hDlg, (LPTSTR)lp);
1785 switch (LOWORD(wp)) {
1788 EndDialog (hDlg, LOWORD(wp));
1792 TCHAR szDir[ MAX_PATH ];
1793 GetCurrentDirectory (MAX_PATH, szDir);
1794 ShellExecute (hDlg, TEXT("print"), (LPTSTR)GetWindowLong (hDlg, DWL_USER), NULL, szDir, SW_HIDE);
1802 BOOL FindAfsInstallationPathByComponent (LPTSTR pszInstallationPath, LPTSTR pszComponent)
1804 *pszInstallationPath = 0;
1806 TCHAR szRegPath[ MAX_PATH ];
1807 wsprintf (szRegPath, TEXT("Software\\TransarcCorporation\\%s\\CurrentVersion"), pszComponent);
1810 if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegPath, &hk) == 0) {
1811 DWORD dwType = REG_SZ;
1812 DWORD dwSize = MAX_PATH;
1814 if (RegQueryValueEx (hk, TEXT("PathName"), NULL, &dwType, (PBYTE)pszInstallationPath, &dwSize) == 0) {
1815 *(LPTSTR)FindBaseFileName (pszInstallationPath) = TEXT('\0');
1817 if (pszInstallationPath[0] && (pszInstallationPath[ lstrlen(pszInstallationPath)-1 ] == TEXT('\\')))
1818 pszInstallationPath[ lstrlen(pszInstallationPath)-1 ] = TEXT('\0');
1824 return !!*pszInstallationPath;
1827 BOOL FindAfsInstallationPath (LPTSTR pszInstallationPath)
1829 if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Client")))
1831 if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Control Center")))
1833 if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Server")))
1835 if (FindAfsInstallationPathByComponent (pszInstallationPath, TEXT("AFS Supplemental Documentation")))
1840 HINSTANCE LoadRichTextControl (void)
1843 if ((hInst = LoadLibrary ("riched20.dll")) != NULL)
1845 if ((hInst = LoadLibrary ("riched32.dll")) != NULL)
1847 if ((hInst = LoadLibrary ("riched.dll")) != NULL)
1849 if ((hInst = LoadLibrary ("richedit.dll")) != NULL)
1854 int SUCALLCONV ShowLicense (char *pszTarget, char *pszSource)
1856 // If the license already lives on this user's machine, don't show
1857 // it again. This only has to be done if the user has never
1858 // accepted the license agreement before (it's part of the setup
1859 // program, so it gets installed if they've accepted it).
1861 // We were handed a relative path of the form:
1862 // Documentation/html/license.rtf
1864 // We'll need to find the AFS installation directory, in order to
1865 // find that Documentation subtree.
1867 BOOL fShowLicense = TRUE;
1869 TCHAR szInstallationPath[ MAX_PATH ];
1870 if (FindAfsInstallationPath (szInstallationPath)) {
1871 TCHAR szLicensePath[ MAX_PATH ];
1872 wsprintf (szLicensePath, TEXT("%s\\%s"), szInstallationPath, pszTarget);
1874 if (GetFileAttributes (szLicensePath) != (DWORD)-1) {
1875 fShowLicense = FALSE;
1879 // Before we can show the license file, we have to prepare the RichEdit
1880 // control. That means loading the appropriate library and calling its
1881 // initialization functions.
1883 HINSTANCE hRichEdit;
1884 if ((hRichEdit = LoadRichTextControl()) != NULL) {
1886 // If we must show the license, do so now. This is a modal dialog,
1887 // so we'll know whether or not the user accepts the license.
1889 if (ModalDialogParam (IDD_LICENSE, GetActiveWindow(), License_DlgProc, (LPARAM)pszSource) == IDCANCEL) {
1890 // The user rejected the license; fail setup
1894 FreeLibrary (hRichEdit);
1897 // The user accepted the license, so we can continue with Setup.
1898 // The license file is installed as part of Setup.
1902 int SUCALLCONV UninstInitialize(HWND hIS, HINSTANCE hIS5, long Reserved)
1904 char szPath[MAX_PATH];
1905 struct APPINFO *pAppInfo;
1907 char *pszSubDir = 0;
1911 bSilentMode = !IsWindowVisible(hIS);
1913 // Which app are we uninstalling?
1914 pAppInfo = GetApp();
1916 ShowError(IDS_CANT_DETERMINE_PRODUCT, 0);
1920 // Get the app's install dir
1921 pszInstallDir = GetAppInstallDir(pAppInfo, FALSE);
1925 // If this app has a custom uninstall func, call it here
1926 if (pAppInfo->pUninstallFunc)
1927 if (!pAppInfo->pUninstallFunc())
1930 if (pAppInfo->pszRegKeysToPreserve)
1931 if (!PreserveConfigInfo(pAppInfo))
1934 // Unconfigure the service, if there is one for this app
1935 if (pAppInfo->pszSvcKey) {
1936 if (IsServiceInstalled(pAppInfo->pszSvcKey))
1937 if (UninstallService(pAppInfo) == 1)
1941 RememberInstallDir(pszInstallDir);
1943 DeleteInUseFiles(pAppInfo, fileInfo);
1945 // Remove the app's bin path from the system path
1946 if (pAppInfo->pszBinPath) {
1947 BuildShortPath(szPath, sizeof(szPath), pszInstallDir, pAppInfo->pszBinPath);
1948 RemoveFromPath(szPath);
1951 // Remove entry from NetworkProvider\Order key in registry
1952 if (pAppInfo->pszNetworkProviderOrder)
1953 RemoveFromNetworkProviderOrder(pAppInfo->pszNetworkProviderOrder);
1955 // Remove any generated subdirectories
1956 if (!bPreserveConfigInfo && pAppInfo->pszDirsToDel) {
1957 for (pszSubDir = pAppInfo->pszDirsToDel; *pszSubDir; pszSubDir += strlen(pszSubDir) + 1)
1958 RemoveDir(ExpandPath(pszSubDir));
1961 // Remove any generated files
1962 if (!bPreserveConfigInfo && pAppInfo->pszFilesToDel) {
1963 for (pszFile = pAppInfo->pszFilesToDel; *pszFile; pszFile += strlen(pszFile) + 1)
1964 RemoveFiles(ExpandPath(pszFile));
1967 // Remove any registry values that IS can't handle
1968 RemoveRegValues(pAppInfo->pRegValues);
1970 RemoveRegValues(pAppInfo->pWinNTRegValues);
1972 RemoveRegValues(pAppInfo->pWin9XRegValues);
1974 // Remove the start menu entries for this app
1975 if (pAppInfo->pszStartMenuEntries) {
1976 DeleteStartMenuEntries(pAppInfo->pszStartMenuEntries);
1980 // Remove the install dir
1981 RemoveDirectory(pszInstallDir);
1986 void SUCALLCONV UninstUnInitialize(HWND hIS, HINSTANCE hIS5, long Reserved)
1988 char *pszInstallDir;
1989 char szDirPath[MAX_PATH];
1991 struct APPINFO *pAppInfo;
1993 // If we just uninstalled the last AFS app, then do some cleanup.
1994 if (IsAppInstalled(&appServer) || IsAppInstalled(&appClient) ||
1995 IsAppInstalled(&appControlCenter) || IsAppInstalled(&appLightClient) ||
1996 IsAppInstalled(&appDocs))
2001 bSilentMode = !IsWindowVisible(hIS);
2003 // Which app did we just uninstall?
2004 pAppInfo = GetApp();
2006 ShowError(IDS_CANT_DETERMINE_PRODUCT, 0);
2010 // Get the app's install dir
2011 pszInstallDir = GetAppInstallDir(pAppInfo, TRUE);
2015 // Remove the reg key we used to remember the app install dir
2016 RegDeleteEntryAlt(UNINSTALL_TEMP_INFO_KEY, REGENTRY_KEY);
2018 // Try to remove the reg key used to store config info, but only
2019 // if there are no app config info sub keys present.
2020 if (!DoSubKeysExist(AFS_PRESERVED_CFG_INFO_KEY))
2021 RegDeleteEntryAlt(AFS_PRESERVED_CFG_INFO_KEY, REGENTRY_KEY);
2023 // Remove the install dir
2024 RemoveDirectory(pszInstallDir);
2026 // Attempt to remove the install root and common directories. The are
2027 // shared and so no single app knows to delete them.
2029 // Strip off the app specific part of the install dir
2030 psz = strrchr(pszInstallDir, '\\');
2034 sprintf(szDirPath, "%s\\%s", pszInstallDir, "Common");
2035 RemoveDirectory(szDirPath);
2037 // Remove the Common directory from the system path
2038 RemoveFromPath(szDirPath);
2040 // Remove all of the documentation dirs
2041 sprintf(szDirPath, "%s\\%s", pszInstallDir, "Documentation");
2042 RemoveDirectoryTree(szDirPath);
2044 // Ok, up to this point we have been removing files we know we
2045 // created. However, after this point we are into the path
2046 // that the user chose for our install root. The default for
2047 // this is IBM/Afs, but they could have chosen anything,
2048 // including a dir or dirs that have other products in them.
2049 // We will check to see if it is IBM\AFS and if it is then we
2050 // will attempt to remove them.
2052 // Back up a level and look for AFS
2053 psz = strrchr(pszInstallDir, '\\');
2055 if (stricmp(psz + 1, "AFS") == 0) {
2056 RemoveDirectory(pszInstallDir);
2061 // Back up a level and look for IBM
2062 psz = strrchr(pszInstallDir, '\\');
2064 if (stricmp(psz + 1, "IBM") == 0) {
2065 RemoveDirectory(pszInstallDir);
2070 // Remove the root afs start menu entry
2071 psz = GetStartMenuRoot();
2074 // Remove everything under our branch
2075 sprintf(szDirPath, "%s\\IBM WebSphere\\Performance Pack\\AFS", psz);
2076 RemoveDirectoryTree(szDirPath);
2078 // Remove the IBM stuff only if the dirs are empty
2079 sprintf(szDirPath, "%s\\IBM WebSphere\\Performance Pack", psz);
2080 if (RemoveDirectory(szDirPath)) {
2081 sprintf(szDirPath, "%s\\IBM WebSphere", psz);
2082 RemoveDirectory(szDirPath);
2085 sprintf(szDirPath, "%s\\IBM AFS", psz);
2086 RemoveDirectoryTree(szDirPath);
2091 BOOLEAN _stdcall DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
2093 if (reason == DLL_PROCESS_ATTACH) {
2094 hinst = (HINSTANCE)dll;
2095 TaLocale_LoadCorrespondingModuleByName (hinst, "afs_setup_utils.dll");
2101 extern "C" int WINAPI Test (HINSTANCE hInst, HINSTANCE hPrev, LPSTR psz, int nCmdShow)
2103 ShowLicense ("TEST", "\\\\fury\\afssetup\\license\\ja_JP.rtf");