//+---------------------------------------------------------------------------- // // File: pbasetup.cpp // // Module: PBASETUP.EXE // // Synopsis: PBA stand alone installer for ValueAdd // // Copyright (c) 1999 Microsoft Corporation // // Author: v-vijayb Created 05/25/99 // //+---------------------------------------------------------------------------- #include "pbamaster.h" #include "cmplat.h" // This is really ugly, we need to consolidate our platform detection code between CM and // the setup components. BOOL IsAtLeastNT5() { CPlatform plat; return plat.IsAtLeastNT5(); } #define OS_NT5 (IsAtLeastNT5()) #include "MemberOfGroup.cpp" TCHAR g_szAppTitle[MAX_PATH]; // global buffer for app. title const TCHAR* const c_pszPBAStpMutex = TEXT("Phone Book Administration Installer"); HRESULT UnregisterAndDeleteDll(PCSTR pszFile);; HRESULT RegisterDll(PCSTR pszFile); BOOL UninstallPBA(HINSTANCE hInstance, LPCSTR szInfPath); BOOL IsAdmin(void); int WINAPI WinMain (HINSTANCE, // hInstance HINSTANCE, //hPrevInstance PSTR, // szCmdLine int) //iCmdShow { HINSTANCE hInstance = GetModuleHandleA(NULL); TCHAR szMsg[MAX_PATH+1]; TCHAR szTemp[MAX_PATH+1]; TCHAR szInfPath[MAX_PATH+1]; TCHAR szCurrentDir[MAX_PATH+1]; DWORD idMsgEnd; DWORD dwFlags; CPlatform pPlatForm; LPTSTR pszCommandLine; const DWORD c_dwNormal = 0; TCHAR c_pszUninstallMode[] = TEXT("/u"); const DWORD c_dwUninstallMode = 0x1; BOOL bUsageError = FALSE; BOOL bAnotherInstanceRunning = FALSE; const int c_NumArgs = 1; MYVERIFY(0 != LoadString(hInstance, IDS_APP_TITLE, g_szAppTitle, MAX_PATH)); if (!pPlatForm.IsAtLeastNT5()) { MYVERIFY(0 != LoadString(hInstance, IDS_NOT_NT5, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK); return (-1); } // // check that the user has sufficient permissions // if (!IsAdmin()) { MYVERIFY(0 != LoadString(hInstance, IDS_NOPERMS_MSG, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK); return (-1); } // // Get the Command Line // pszCommandLine = GetCommandLine(); // // Setup the Class to process the command line args // ZeroMemory(szTemp, sizeof(szTemp)); ZeroMemory(szInfPath, sizeof(szInfPath)); ArgStruct Args[c_NumArgs]; Args[0].pszArgString = c_pszUninstallMode; Args[0].dwFlagModifier = c_dwUninstallMode; { // Make sure ArgProcessor gets destructed properly and we don't leak mem CProcessCmdLn ArgProcessor(c_NumArgs, (ArgStruct*)Args, TRUE, TRUE); //bSkipFirstToken == TRUE, bBlankCmdLnOkay == TRUE if (ArgProcessor.GetCmdLineArgs(pszCommandLine, &dwFlags, szTemp, MAX_PATH)) { CNamedMutex CmPBAMutex; if (CmPBAMutex.Lock(c_pszPBAStpMutex, FALSE, 0)) { // // We got the mutex lock, so Construct the Inf Paths and continue. // Note that we don't use any file arguments passed into cmakstp. // It is setup to do so, but we don't need it. // MYVERIFY(0 != GetCurrentDirectory(MAX_PATH, szCurrentDir)); MYVERIFY(CELEMS(szInfPath) > (UINT)wsprintf(szInfPath, TEXT("%s\\pbasetup.inf"), szCurrentDir)); if (c_dwNormal == dwFlags) { if (InstallPBA(hInstance, szInfPath)) { MYVERIFY(0 != LoadString(hInstance, IDS_SUCCESSFUL, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK | MB_APPLMODAL | MB_TOPMOST | MB_SETFOREGROUND); } } else if (c_dwUninstallMode & dwFlags) { // Confirm if the user wants to remove the program MYVERIFY(0 != LoadString(hInstance, IDS_REMOVEPBA, szMsg, MAX_PATH)); if (MessageBox(NULL, szMsg, g_szAppTitle, MB_YESNO | MB_APPLMODAL | MB_TOPMOST | MB_SETFOREGROUND) != IDYES) { ExitProcess(0); return (0); } if (UninstallPBA(hInstance, szTemp)) { MYVERIFY(0 != LoadString(hInstance, IDS_REMOVESUCCESSFUL, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK | MB_APPLMODAL | MB_TOPMOST | MB_SETFOREGROUND); } } else { // // unsupported switch // bUsageError = TRUE; } } else { bAnotherInstanceRunning = TRUE; } } else { bUsageError = TRUE; } } if (bUsageError) { MYVERIFY(0 != LoadString(hInstance, IDS_USAGE_MSG, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK); } else if (bAnotherInstanceRunning) { MYVERIFY(0 != LoadString(hInstance, IDS_INUSE_MSG, szMsg, MAX_PATH)); MessageBox(NULL, szMsg, g_szAppTitle, MB_OK); } ExitProcess(0); return (0); } const TCHAR* const c_szDaoClientsPath = TEXT("SOFTWARE\\Microsoft\\Shared Tools\\DAO\\Clients"); const TCHAR* c_szMSSharedDAO360Path = TEXT("Microsoft Shared\\DAO"); const TCHAR* c_szCommonFilesDir = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); //+--------------------------------------------------------------------------- // // Function: HrGetPbaInstallPath // // Purpose: Get the install path for pbadmin.exe. // // Arguments: pszCpaPath -- buffer to hold the install path of PBA. // dwNumChars -- the number of characters that the buffer can hold. // // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 19 OCT 1998 // // Notes: // HRESULT HrGetPbaInstallPath(PTCHAR pszCpaPath, DWORD dwNumChars) { HRESULT hr = E_FAIL; HKEY hKey; BOOL bFound = FALSE; DWORD lError; // We need to setup the custom DIRID so that CPA will install // to the correct location. First get the path from the system. // ZeroMemory(pszCpaPath, sizeof(TCHAR)*dwNumChars); lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, 0, KEY_READ, &hKey); if (lError == ERROR_SUCCESS) { TCHAR szCurrentValue[MAX_PATH+1]; TCHAR szCurrentData[MAX_PATH+1]; DWORD dwValueSize = MAX_PATH; DWORD dwDataSize = MAX_PATH; DWORD dwType; DWORD dwIndex = 0; hr = S_OK; while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType, (LPBYTE)szCurrentData, &dwDataSize)) { _strlwr(szCurrentValue); if (NULL != strstr(szCurrentValue, TEXT("pbadmin.exe"))) { // // Then we have found the PBA path // TCHAR* pszTemp = strrchr(szCurrentValue, '\\'); if (NULL != pszTemp) { *pszTemp = L'\0'; lstrcpy(pszCpaPath, szCurrentValue); bFound = TRUE; break; } } dwValueSize = MAX_PATH; dwDataSize = MAX_PATH; dwIndex++; } RegCloseKey(hKey); } if (!bFound) { BOOL bTmp; // This is a fresh install of PBA, don't return an error // bTmp = SHGetSpecialFolderPath(NULL, pszCpaPath, CSIDL_PROGRAM_FILES, FALSE); if (bTmp) { lstrcat(pszCpaPath, TEXT("\\PBA")); hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } return hr; } //+--------------------------------------------------------------------------- // // Function: RefCountPbaSharedDlls // // Purpose: Reference count and register/unregister all of the PBAdmin // shared components. // // Arguments: BOOL bIncrement -- if TRUE, then increment the ref count, // else decrement it // // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 9 OCT 1998 // // Notes: // HRESULT RefCountPbaSharedDlls(BOOL bIncrement) { HRESULT hr = S_OK; HKEY hKey; TCHAR szSystemDir[MAX_PATH+1]; TCHAR szDaoPath[MAX_PATH+1], szCommonFilesPath[MAX_PATH+1]; DWORD dwSize; DWORD dwCount; LONG lResult; const UINT uNumDlls = 5; const UINT uStringLen = 12 + 1; const TCHAR* const c_szSsFmt = TEXT("%s\\%s"); const TCHAR* const c_szSharedDllsPath = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDlls"); TCHAR mszDlls[uNumDlls][uStringLen] = { "comctl32.ocx", "comdlg32.ocx", "msinet.ocx", "tabctl32.ocx", "dao360.dll" }; TCHAR mszDllPaths[uNumDlls][MAX_PATH]; // // All of the Dlls that we ref count are in the system directory, except for Dao350.dll. // Thus we want to append the system directory path to our filenames and handle dao last. // if (0 == GetSystemDirectory(szSystemDir, MAX_PATH)) { return E_UNEXPECTED; } for (int i = 0; i < (uNumDlls-1) ; i++) { wsprintf(mszDllPaths[i], c_szSsFmt, szSystemDir, mszDlls[i]); } // // Now write out the dao360.dll path. // if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szCommonFilesDir, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize)) { dwSize = sizeof(szCommonFilesPath); lResult = RegQueryValueEx(hKey, TEXT("CommonFilesDir"), NULL, NULL,(LPBYTE)szCommonFilesPath, &dwSize); RegCloseKey(hKey); } if (ERROR_SUCCESS != lResult) { _tcscpy(szCommonFilesPath, TEXT("c:\\Program Files\\Common Files")); } wsprintf(szDaoPath, TEXT("%s\\%s"), szCommonFilesPath, c_szMSSharedDAO360Path); wsprintf(mszDllPaths[i], c_szSsFmt, szDaoPath, mszDlls[i]); // // Open the shared DLL key and start enumerating our multi-sz with all of our dll's // to add. // if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szSharedDllsPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize)) // using dwSize as a temp to hold the disposition value { for (int i=0; i < uNumDlls; i++) { dwSize = sizeof(DWORD); lResult = RegQueryValueEx(hKey, mszDllPaths[i], NULL, NULL,(LPBYTE)&dwCount, &dwSize); if (ERROR_SUCCESS == lResult) { // // Increment or decrement as appropriate. Make sure not to decrement 0 // if (0 != dwCount || bIncrement) { dwCount = dwCount + (bIncrement ? 1 : -1); } } else if (ERROR_FILE_NOT_FOUND == lResult) { if (bIncrement) { // // The the value doesn't yet exist. Set the count to 1. // dwCount = 1; } else { // // We are decrementing and we couldn't find the DLL, nothing to // change for the count but we should still delete the dll. // dwCount = 0; } } else { hr = S_FALSE; continue; } // // Not that we have determined the ref count, do something about it. // if (dwCount == 0) { // // We don't want to delete dao350.dll, but otherwise we need to delete // the file if it has a zero refcount. // if (CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, mszDlls[i], -1, TEXT("dao360.dll"), -1)) { hr = UnregisterAndDeleteDll(mszDllPaths[i]); if (FAILED(hr)) { // // Don't fail the setup over a file that we couldn't unregister or // couldn't delete // hr = S_FALSE; } } RegDeleteValue(hKey, mszDllPaths[i]); } else { // // Set the value to its new count. // if (ERROR_SUCCESS != RegSetValueEx(hKey, mszDllPaths[i], 0, REG_DWORD, (LPBYTE)&dwCount, sizeof(DWORD))) { hr = S_FALSE; } // // If we are incrementing the count then we should register the dll. // if (bIncrement) { hr = RegisterDll(mszDllPaths[i]); } } } RegCloseKey(hKey); } /// TraceError("RefCountPbaSharedDlls", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: UnregisterAndDeleteDll // // Purpose: Unregister and delete the given COM component // // Arguments: pszFile -- The full path to the file to unregister and delete // // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 9 OCT 1998 // // Notes: // HRESULT UnregisterAndDeleteDll(PCSTR pszFile) { HINSTANCE hLib = NULL; FARPROC pfncUnRegister; HRESULT hr = S_OK; if ((NULL == pszFile) || (L'\0' == pszFile[0])) { return E_INVALIDARG; } hLib = LoadLibrary(pszFile); if (NULL != hLib) { pfncUnRegister = GetProcAddress(hLib, "DllUnregisterServer"); if (NULL != pfncUnRegister) { hr = (HRESULT)(pfncUnRegister)(); if (SUCCEEDED(hr)) { FreeLibrary(hLib); hLib = NULL; // You can add this back in as long as you are sure that we copied the file down and thus // should be deleting it when the ref count is Zero. // This was removed because PBA setup is moving to Value Add and because of bug 323231 // if (!DeleteFile(pszFile)) // { // hr = S_FALSE; // } } } else { hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); } } else { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } if (NULL != hLib) { FreeLibrary(hLib); } /// TraceError("UnregisterAndDeleteDll", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: RegisterDll // // Purpose: Register the given COM component // // Arguments: pszFile -- The full path to the file to register // // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 9 OCT 1998 // // Notes: // HRESULT RegisterDll(PCSTR pszFile) { HINSTANCE hLib = NULL; FARPROC pfncRegister; HRESULT hr = S_OK; if ((NULL == pszFile) || (L'\0' == pszFile[0])) { return E_INVALIDARG; } hLib = LoadLibrary(pszFile); if (NULL != hLib) { pfncRegister = GetProcAddress(hLib, "DllRegisterServer"); if (NULL != pfncRegister) { hr = (HRESULT)(pfncRegister)(); } else { hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); } } else { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } if (NULL != hLib) { FreeLibrary(hLib); } /// TraceError("RegisterDll", hr); return hr; } //+---------------------------------------------------------------------------- // // Function: InstallPBA // // Synopsis: This function is responsible for installing PBA // // Arguments: HINSTANCE hInstance - Exe Instance handle for resources // LPCTSTR szInfPath - Path of the INF to install from // // Returns: BOOL - returns TRUE if successful. // // History: v-vijayb Created Header 5/25/99 // //+---------------------------------------------------------------------------- BOOL InstallPBA(HINSTANCE hInstance, LPCSTR szInfPath) { BOOL fInstalled = FALSE; TCHAR szTemp[MAX_PATH+1]; // // Check to see that these files exist // if (!FileExists(szInfPath)) { wsprintf(szTemp, TEXT("InstallPBA, unable to find %s"), szInfPath); MessageBox(NULL, szTemp, g_szAppTitle, MB_OK); return (FALSE); } if (HrGetPbaInstallPath(szTemp, sizeof(szTemp)) == S_OK) { HKEY hKey; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { RegSetValueEx(hKey, "PBAPath", 0, REG_SZ, (PBYTE) szTemp, lstrlen(szTemp) + sizeof(TCHAR)); RegCloseKey(hKey); } } MYVERIFY(SUCCEEDED(LaunchInfSection(szInfPath, TEXT("DefaultInstall"), g_szAppTitle, 0))); RefCountPbaSharedDlls(TRUE); fInstalled = TRUE; return (fInstalled); } // InstallPBA() //+---------------------------------------------------------------------------- // // Function: UnInstallPBA // // Synopsis: This function is responsible for uninstalling PBA // // Arguments: HINSTANCE hInstance - Exe Instance handle for resources // LPCTSTR szInfPath - Path of the INF to install from // // Returns: BOOL - returns TRUE if successful. // // History: v-vijayb Created Header 5/25/99 // //+---------------------------------------------------------------------------- BOOL UninstallPBA(HINSTANCE hInstance, LPCSTR szInfPath) { BOOL fUninstalled = FALSE; TCHAR szTemp[MAX_PATH+1]; // // Check to see that these files exist // if (!FileExists(szInfPath)) { wsprintf(szTemp, TEXT("UninstallPBA, unable to find %s"), szInfPath); MessageBox(NULL, szTemp, g_szAppTitle, MB_OK); return (FALSE); } MYVERIFY(SUCCEEDED(LaunchInfSection(szInfPath, TEXT("Uninstall"), g_szAppTitle, 0))); RefCountPbaSharedDlls(FALSE); fUninstalled = TRUE; return (fUninstalled); } // UninstallPBA()