windows-nt/Source/XPSP1/NT/net/config/netoc/nccpa.cpp
2020-09-26 16:20:57 +08:00

791 lines
20 KiB
C++

//+---------------------------------------------------------------------------
//
// 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 <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#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;
}
*/