//+--------------------------------------------------------------------------- // // File: NCNetCPA.CPP // // Module: NetOC.DLL // // Synopsis: Implements the dll entry points required to integrate into // NetOC.DLL the installation of the following components. // // NETCPS // // Copyright (C) Microsoft Corporation. All rights reserved. // // Author: Anas Jarrah (a-anasj) Created 3/9/98 // //+--------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include extern CComModule _Module; #include #include "ncatl.h" #include "resource.h" #include "nccm.h" // // Define Globals // WCHAR g_szCpaPath[MAX_PATH+1]; WCHAR g_szDaoPath[MAX_PATH+1]; // // Define Constants // const DWORD c_dwCpaDirID = 123176; // just must be larger than DIRID_USER = 0x8000; const DWORD c_dwDaoDirID = 123177; // just must be larger than DIRID_USER = 0x8000; const WCHAR* const c_szDaoClientsPath = L"SOFTWARE\\Microsoft\\Shared Tools\\DAO\\Clients"; const WCHAR* const c_szCommonFilesPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion"; const WCHAR* const c_szCommonFilesDirValue = L"CommonFilesDir"; HRESULT HrGetPBAPathIfInstalled(PWSTR pszCpaPath, DWORD dwNumChars) { HRESULT hr; HKEY hKey; BOOL bFound = FALSE; // We need to see if PBA is installed or not. If it is then we want to // add back the PBA start menu link. If it isn't, then we want to do nothing // with PBA. // ZeroMemory(pszCpaPath, sizeof(WCHAR)*dwNumChars); hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, KEY_READ, &hKey); if (SUCCEEDED(hr)) { WCHAR szCurrentValue[MAX_PATH+1]; WCHAR szCurrentData[MAX_PATH+1]; DWORD dwValueSize = MAX_PATH; DWORD dwDataSize = MAX_PATH; DWORD dwType; DWORD dwIndex = 0; while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType, (LPBYTE)szCurrentData, &dwDataSize)) { _wcslwr(szCurrentValue); if (NULL != wcsstr(szCurrentValue, L"pbadmin.exe")) { // // Then we have found the PBA path // WCHAR* pszTemp = wcsrchr(szCurrentValue, L'\\'); if (NULL != pszTemp) { *pszTemp = L'\0'; lstrcpyW(pszCpaPath, szCurrentValue); bFound = TRUE; break; } } dwValueSize = MAX_PATH; dwDataSize = MAX_PATH; dwIndex++; } RegCloseKey(hKey); } if (!bFound) { // We didn't find PBA, so lets return S_FALSE // hr = S_FALSE; } else { hr = S_OK; } return hr; } BOOL GetAdminToolsFolder(PWSTR pszAdminTools) { BOOL bReturn = FALSE; if (pszAdminTools) { bReturn = SHGetSpecialFolderPath(NULL, pszAdminTools, CSIDL_COMMON_PROGRAMS, TRUE); if (bReturn) { // Now Append Administrative Tools // lstrcat(pszAdminTools, SzLoadIds(IDS_OC_ADMIN_TOOLS)); } } return bReturn; } HRESULT HrCreatePbaShortcut(PWSTR pszCpaPath) { HRESULT hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { IShellLink *psl = NULL; hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, //CLSCTX_LOCAL_SERVER, IID_IShellLink, (LPVOID*)&psl); if (SUCCEEDED(hr)) { IPersistFile *ppf = NULL; // Set up the properties of the Shortcut // static const WCHAR c_szPbAdmin[] = L"\\pbadmin.exe"; WCHAR szPathToPbadmin[MAX_PATH+1] = {0}; DWORD dwLen = lstrlen(c_szPbAdmin) + lstrlen(pszCpaPath) + 1; if (MAX_PATH >= dwLen) { // Set the Path to pbadmin.exe // lstrcpy(szPathToPbadmin, pszCpaPath); lstrcat(szPathToPbadmin, c_szPbAdmin); hr = psl->SetPath(szPathToPbadmin); if (SUCCEEDED(hr)) { // Set the Description to Phone Book Administrator // hr = psl->SetDescription(SzLoadIds(IDS_OC_PBA_DESC)); if (SUCCEEDED(hr)) { hr = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); if (SUCCEEDED(hr)) { WCHAR szAdminTools[MAX_PATH+1] = {0}; if (GetAdminToolsFolder(szAdminTools)) { // Create the link file. // hr = ppf->Save(szAdminTools, TRUE); } ReleaseObj(ppf); } } } } ReleaseObj(psl); } CoUninitialize(); } return hr; } //+--------------------------------------------------------------------------- // // Function: HrOcCpaPreQueueFiles // // Purpose: Called by optional components installer code to handle // additional installation requirements for PhoneBook Server. // // Arguments: // pnocd [in] Pointer to NETOC data. // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 18 Sep 1998 // // Notes: // HRESULT HrOcCpaPreQueueFiles(PNETOCDATA pnocd) { HRESULT hr = S_OK; switch ( pnocd->eit ) { case IT_UPGRADE: WCHAR szPbaInstallPath[MAX_PATH+1]; hr = HrGetPBAPathIfInstalled(szPbaInstallPath, MAX_PATH); if (S_OK == hr) { HrCreatePbaShortcut(szPbaInstallPath); } break; case IT_INSTALL: case IT_REMOVE: break; } TraceError("HrOcCpaPreQueueFiles", hr); return hr; } /* //+--------------------------------------------------------------------------- // // Function: HrOcCpaPreQueueFiles // // Purpose: Called by optional components installer code to handle // additional installation requirements for PhoneBook Server. // // Arguments: // pnocd [in] Pointer to NETOC data. // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 18 Sep 1998 // // Notes: // HRESULT HrOcCpaPreQueueFiles(PNETOCDATA pnocd) { HRESULT hr = S_OK; switch ( pnocd->eit ) { case IT_UPGRADE: case IT_INSTALL: case IT_REMOVE: // // Get the PBA install Dir. // hr = HrGetPbaInstallPath(g_szCpaPath, celems(g_szCpaPath)); if (SUCCEEDED(hr)) { // Next Create the CPA Dir ID // hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd); if (SUCCEEDED(hr)) { if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCpaDirID, g_szCpaPath)) { hr = HRESULT_FROM_WIN32(GetLastError()); } } } // // Now query the system for the DAO350 install path // if (SUCCEEDED (hr)) { hr = HrGetDaoInstallPath(g_szDaoPath, celems(g_szDaoPath)); if (SUCCEEDED(hr)) { // Next Create the DAO Dir ID // hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd); if (SUCCEEDED(hr)) { if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwDaoDirID, g_szDaoPath)) { hr = HRESULT_FROM_WIN32(GetLastError()); } } } } break; } TraceError("HrOcCpaPreQueueFiles", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrOcCpaOnInstall // // Purpose: Called by optional components installer code to handle // additional installation requirements for PhoneBook Server. // // Arguments: // pnocd [in] Pointer to NETOC data. // // Returns: S_OK if successfull, Win32 error otherwise. // // Author: quintinb 18 Sep 1998 // // Notes: // HRESULT HrOcCpaOnInstall(PNETOCDATA pnocd) { HRESULT hr = S_OK; switch ( pnocd->eit ) { case IT_INSTALL: hr = RefCountPbaSharedDlls(TRUE); // bIncrement = TRUE break; case IT_REMOVE: hr = RefCountPbaSharedDlls(FALSE); // bIncrement = FALSE break; case IT_UPGRADE: DeleteOldNtopLinks(); break; case IT_UNKNOWN: case IT_NO_CHANGE: break; } TraceError("HrOcCpaOnInstall", hr); 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; WCHAR szSystemDir[MAX_PATH+1]; DWORD dwSize; DWORD dwCount; LONG lResult; const UINT uNumDlls = 6; const UINT uStringLen = 12 + 1; const WCHAR* const c_szSsFmt = L"%s\\%s"; const WCHAR* const c_szSharedDllsPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDlls"; WCHAR mszDlls[uNumDlls][uStringLen] = { L"comctl32.ocx", L"comdlg32.ocx", L"msinet.ocx", L"tabctl32.ocx", L"dbgrid32.ocx", L"dao350.dll" }; WCHAR 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++) { wsprintfW(mszDllPaths[i], c_szSsFmt, szSystemDir, mszDlls[i]); } // // Now write out the dao350.dll path. // wsprintfW(mszDllPaths[i], c_szSsFmt, g_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 = RegQueryValueExW(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 (0 != lstrcmpiW(mszDlls[i], L"dao350.dll")) { 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(PCWSTR 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 = (pfncUnRegister)(); if (SUCCEEDED(hr)) { FreeLibrary(hLib); hLib = NULL; // 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(PCWSTR 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 = (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: 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(PWSTR pszCpaPath, DWORD dwNumChars) { HRESULT hr; HKEY hKey; BOOL bFound = FALSE; // 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(WCHAR)*dwNumChars); hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, KEY_READ, &hKey); if (SUCCEEDED(hr)) { WCHAR szCurrentValue[MAX_PATH+1]; WCHAR szCurrentData[MAX_PATH+1]; DWORD dwValueSize = MAX_PATH; DWORD dwDataSize = MAX_PATH; DWORD dwType; DWORD dwIndex = 0; while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType, (LPBYTE)szCurrentData, &dwDataSize)) { _wcslwr(szCurrentValue); if (NULL != wcsstr(szCurrentValue, L"pbadmin.exe")) { // // Then we have found the PBA path // WCHAR* pszTemp = wcsrchr(szCurrentValue, L'\\'); if (NULL != pszTemp) { *pszTemp = L'\0'; lstrcpyW(pszCpaPath, szCurrentValue); bFound = TRUE; break; } } dwValueSize = MAX_PATH; dwDataSize = MAX_PATH; dwIndex++; } RegCloseKey(hKey); } if (!bFound) { // This is a fresh install of CPA, don't return an error // hr = SHGetSpecialFolderPath(NULL, pszCpaPath, CSIDL_PROGRAM_FILES, FALSE); if (SUCCEEDED(hr)) { lstrcatW(pszCpaPath, L"\\PBA"); } } return hr; } //+--------------------------------------------------------------------------- // // Function: HrGetDaoInstallPath // // 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 HrGetDaoInstallPath(PWSTR pszDaoPath, DWORD dwNumChars) { HRESULT hr; HKEY hKey; // We need to setup the custom DIRID so that CPA will install // to the correct location. First get the path from the system. // ZeroMemory(pszDaoPath, sizeof(WCHAR)*dwNumChars); hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szCommonFilesPath, KEY_ALL_ACCESS, &hKey); if (SUCCEEDED(hr)) { DWORD dwSize = sizeof(WCHAR)*dwNumChars; // // Try to get the CommonFilesDir value from the registry, but if it doesn't exist // then create it. // if (ERROR_SUCCESS != RegQueryValueExW(hKey, c_szCommonFilesDirValue, NULL, NULL, (LPBYTE)pszDaoPath, &dwSize)) { hr = SHGetSpecialFolderPath(NULL, pszDaoPath, CSIDL_PROGRAM_FILES, FALSE); if (SUCCEEDED(hr)) { // // QBBUG -- Common files is localizable. Make a string resource. // lstrcatW(pszDaoPath, (PWSTR)SzLoadIds(IDS_OC_COMMON_FILES)); // // Now set the regvalue // hr = HrRegSetValueEx(hKey, c_szCommonFilesDirValue, REG_SZ, (const BYTE*)pszDaoPath, sizeof(WCHAR)*dwNumChars); } } RegCloseKey(hKey); } if (SUCCEEDED(hr)) { // // QBBUG -- should Microsoft shared be a string resource? // lstrcatW(g_szDaoPath, (PWSTR)SzLoadIds(IDS_OC_MS_SHARED_DAO)); } return hr; } */