|
|
//+----------------------------------------------------------------------------
//
// File: common.cpp
//
// Module: CMSTP.EXE
//
// Synopsis: This source file contains functions common to several
// different aspects of the CM profile installer (install,
// uninstall, migration).
//
// Copyright (c) 1997-1999 Microsoft Corporation
//
// Author: quintinb Created 11/18/97
//
//+----------------------------------------------------------------------------
#include "cmmaster.h"
//
// for GetPhoneBookPath
//
#include "getpbk.cpp"
//
// For GetAllUsersCmDir
//
#include "allcmdir.cpp"
//
// Need the definition for CM_PBK_FILTER_PREFIX
//
#include "cmdefs.h"
//
// Include the Connections folder specific headers
//
//#include "shlobjp.h"
//#include <objbase.h> // needed for initing guids
//#include <initguid.h> // DON'T CHANGE the ORDER of these header files unless you know what you are doing
//#include <oleguid.h> // IID_IDataObject
//#include <shlguid.h> // IID_IShellFolder
//+----------------------------------------------------------------------------
//
// Function: GetHiddenPhoneBookPath
//
// Synopsis: This function returns the path for the hidden RAS pbk to contain
// the PPP connectoid of a double dial connection. Before returing
// it checks to see if the phonebook exists or not. If the phonebook
// doesn't exist then it returns FALSE. If the function returns
// TRUE the path allocated and stored in *ppszPhonebook must be
// freed using CmFree.
//
// Arguments: LPCTSTR pszProfileDir - full path to the profile directory (dir where cmp resides)
// LPTSTR* ppszPhonebook - pointer to hold the allocated path
//
// Returns: BOOL - TRUE if the phonebook path can be constructed and the
// phonebook file exists.
//
// History: quintinb Created Header 04/14/00
//
//+----------------------------------------------------------------------------
BOOL GetHiddenPhoneBookPath(LPCTSTR pszProfileDir, LPTSTR* ppszPhonebook) { // REVIEW: quintinb 12-18-00
// This function returns the wrong path for the Hidden phonebook. This file is
// now named _CMPhone (no .pbk extension) and is now located in the same directory
// as the rasphone.pbk file on NT4, NT5, and whistler. Note that this function isn't
// used on Win9x. Since the problem was low priority (leaving a few K file on the users
// harddrive at uninstall time, we punted the problem as it was close to Beta2 lockdown.
//
BOOL bReturn = FALSE;
if (pszProfileDir && ppszPhonebook && (TEXT('\0') != pszProfileDir[0])) { LPTSTR pszPathToReturn = NULL;
*ppszPhonebook = (LPTSTR) CmMalloc((lstrlen(pszProfileDir) + lstrlen(CM_PBK_FILTER_PREFIX) + 13) * sizeof(TCHAR));
MYDBGASSERT(*ppszPhonebook);
if (*ppszPhonebook) { //
// Note -- The connection enumerator (netman) will filter out notifications
// for connections created in files with the CM_PBK_FILTER_PREFIX in their
// name.
//
wsprintf(*ppszPhonebook, TEXT("%s\\%sphone.pbk"), pszProfileDir, CM_PBK_FILTER_PREFIX);
bReturn = FileExists(*ppszPhonebook); } }
if (FALSE == bReturn) { CmFree(*ppszPhonebook); *ppszPhonebook = NULL; }
return bReturn; }
//+----------------------------------------------------------------------------
//
// Function: RemoveShowIconFromRunPostSetupCommands
//
// Synopsis: This function removes showicon.exe from the RunPostSetupCommands
// section of old 1.0 Infs.
//
// Arguments: LPCTSTR szInfFile - the inf file to remove showicon.exe from
//
// Returns: Nothing
//
// History: quintinb Created Header 10/22/98
//
//+----------------------------------------------------------------------------
void RemoveShowIconFromRunPostSetupCommands(LPCTSTR szInfFile) { DWORD dwSize = 1024; DWORD dwSizeNeeded = 1024; TCHAR* pszBuffer = NULL; TCHAR* pszNewBuffer = NULL; const TCHAR* const c_pszRunPostSetupCommandsSection = TEXT("RunPostSetupCommandsSection"); const TCHAR* const c_pszShowIcon = TEXT("showicon.exe"); pszBuffer = (TCHAR*)CmMalloc(sizeof(TCHAR)*dwSize); if (NULL == pszBuffer) { CMASSERTMSG(FALSE, TEXT("RemoveShowIconFromRunPostSetupCommands -- CmMalloc returned a NULL pointer.")); goto exit; }
dwSizeNeeded = GetPrivateProfileSection(c_pszRunPostSetupCommandsSection, pszBuffer, dwSize, szInfFile);
while((dwSizeNeeded + 2) == dwSize) { //
// the buffer isn't big enough, try again.
//
dwSize += 1024;
MYDBGASSERT(dwSize <= 32*1024); // 32767 is the max size on Win95
CmFree(pszBuffer);
pszBuffer = (TCHAR*)CmMalloc(sizeof(TCHAR)*dwSize); if (NULL == pszBuffer) { CMASSERTMSG(FALSE, TEXT("RemoveShowIconFromRunPostSetupCommands -- CmMalloc returned a NULL pointer.")); goto exit; }
dwSizeNeeded = GetPrivateProfileSection(c_pszRunPostSetupCommandsSection, pszBuffer, dwSize, szInfFile); }
//
// Search the Buffer to find and remove and occurences of showicon.exe
//
if (0 != dwSizeNeeded) { //
// Allocate a new buffer of the same size.
//
pszNewBuffer = (TCHAR*)CmMalloc(sizeof(TCHAR)*dwSize); if (NULL == pszNewBuffer) { CMASSERTMSG(FALSE, TEXT("RemoveShowIconFromRunPostSetupCommands -- CmMalloc returned a NULL pointer.")); goto exit; }
//
// Use Temp pointers to walk the buffers
//
TCHAR *pszNewBufferTemp = pszNewBuffer; TCHAR *pszBufferTemp = pszBuffer;
while (TEXT('\0') != pszBufferTemp[0]) { //
// If the string isn't showicon.exe then go ahead and copy it to the new
// buffer. Otherwise, don't.
//
if (0 != lstrcmpi(c_pszShowIcon, pszBufferTemp)) { lstrcpy(pszNewBufferTemp, pszBufferTemp); pszNewBufferTemp = pszNewBufferTemp + (lstrlen(pszNewBufferTemp) + 1)*sizeof(TCHAR); }
pszBufferTemp = pszBufferTemp + (lstrlen(pszBufferTemp) + 1)*sizeof(TCHAR); }
//
// Erase the current Section and then rewrite it with the new section
//
MYVERIFY(0 != WritePrivateProfileSection(c_pszRunPostSetupCommandsSection, NULL, szInfFile));
MYVERIFY(0 != WritePrivateProfileSection(c_pszRunPostSetupCommandsSection, pszNewBuffer, szInfFile)); }
exit: CmFree(pszBuffer); CmFree(pszNewBuffer); }
//+----------------------------------------------------------------------------
//
// Function: HrRegDeleteKeyTree
//
// Synopsis: Deletes an entire registry hive.
//
// Arguments: hkeyParent [in] Handle to open key where the desired key resides.
// szRemoveKey [in] Name of key to delete.
//
// Returns: HRESULT HrRegDeleteKeyTree -
//
// History: danielwe 25 Feb 1997
// borrowed and modified -- quintinb -- 4-2-98
//
//+----------------------------------------------------------------------------
HRESULT HrRegDeleteKeyTree (HKEY hkeyParent, LPCTSTR szRemoveKey) { LONG lResult; HRESULT hr; MYDBGASSERT(hkeyParent); MYDBGASSERT(szRemoveKey);
// Open the key we want to remove
HKEY hkeyRemove; lResult = RegOpenKeyEx(hkeyParent, szRemoveKey, 0, KEY_ALL_ACCESS, &hkeyRemove); hr = HRESULT_FROM_WIN32 (lResult);
if (SUCCEEDED(hr)) { TCHAR szValueName [MAX_PATH+1]; DWORD cchBuffSize = MAX_PATH; FILETIME ft;
// Enum the keys children, and remove those sub-trees
while (ERROR_NO_MORE_ITEMS != (lResult = RegEnumKeyEx(hkeyRemove, 0, szValueName, &cchBuffSize, NULL, NULL, NULL, &ft))) { MYVERIFY(SUCCEEDED(HrRegDeleteKeyTree (hkeyRemove, szValueName))); cchBuffSize = MAX_PATH; } MYVERIFY(ERROR_SUCCESS == RegCloseKey (hkeyRemove));
if ((ERROR_SUCCESS == lResult) || (ERROR_NO_MORE_ITEMS == lResult)) { lResult = RegDeleteKey(hkeyParent, szRemoveKey); }
hr = HRESULT_FROM_WIN32 (lResult); }
return hr; }
//+----------------------------------------------------------------------------
//
// Function: RemovePhonebookEntry
//
// Synopsis: This function loads RAS dynamically and then deletes the specified
// connectoids. It will either delete only the connectoid exactly
// specified by the phonebook and entry name (bMatchSimilarEntries == FALSE)
// or it will enumerate all entries in the phonebook and delete any
// entry that matches the first lstrlen(pszEntryName) chars of the given
// connectoid name (thus deleting backup and tunnel connectoids). Note
// that on NT5 we must set the <> parameter of the connectoid to "" so
// that the RasCustomDeleteEntryNotify will not get called and thus have
// cmstp.exe /u launched on the connection.
//
// Arguments: LPTSTR pszEntryName - the long service name of the profile to delete
// LPTSTR pszPhonebook - the full path to the pbk file to delete entries from
// BOOL bMatchSimilarEntries - whether the function should delete similarly
// named connectoids or only the exact connectoid
// specified.
//
// Returns: BOOL - returns TRUE if the function was successful, FALSE otherwise
//
// History: quintinb 7/14/98 Created
// quintinb 7/27/99 rewrote to include deleting a single connectoid or
// enumerating to delete all similarly named connectoids
//
//+----------------------------------------------------------------------------
BOOL RemovePhonebookEntry(LPCTSTR pszEntryName, LPTSTR pszPhonebook, BOOL bMatchSimilarEntries) { pfnRasDeleteEntrySpec pfnDeleteEntry; pfnRasEnumEntriesSpec pfnEnumEntries; pfnRasSetEntryPropertiesSpec pfnSetEntryProperties; pfnRasSetCredentialsSpec pfnSetCredentials;
DWORD dwStructSize; DWORD dwSize; DWORD dwNum; DWORD dwRet; DWORD dwIdx; DWORD dwLen; CPlatform plat; BOOL bReturn = FALSE; BOOL bExit; TCHAR szTemp[MAX_PATH+1]; RASENTRYNAME* pRasEntries = NULL; RASENTRYNAME* pCurrentRasEntry = NULL;
//
// Check Inputs
//
MYDBGASSERT(NULL != pszEntryName); MYDBGASSERT((NULL == pszPhonebook) || (TEXT('\0') != pszPhonebook[0]));
if ((NULL == pszEntryName) || ((NULL != pszPhonebook) && (TEXT('\0') == pszPhonebook[0]))) { CMTRACE(TEXT("RemovePhonebookEntry -- Invalid Parameter passed in.")); goto exit; } //
// Get Function Pointers for the Ras Apis that we need
//
if(!GetRasApis(&pfnDeleteEntry, &pfnEnumEntries, &pfnSetEntryProperties, NULL, NULL, (plat.IsAtLeastNT5() ? &pfnSetCredentials : NULL))) { CMTRACE(TEXT("RemovePhonebookEntry -- Unable to get RAS apis.")); bReturn = FALSE; goto exit; }
//
// Setup the Structure Sizes correctly
//
if (plat.IsAtLeastNT5()) { dwStructSize = sizeof(RASENTRYNAME_V500); } else { dwStructSize = sizeof(RASENTRYNAME); }
//
// Init the Size to one struct and dwNum to zero entries
//
bExit = FALSE; dwSize = dwStructSize*1; dwNum = 0;
do { pRasEntries = (RASENTRYNAME*)CmMalloc(dwSize);
if (NULL == pRasEntries) { CMASSERTMSG(FALSE, TEXT("RemovePhonebookEntry -- CmMalloc returned a NULL pointer.")); goto exit; }
//
// Set the struct size
//
pRasEntries->dwSize = dwStructSize;
dwRet = (pfnEnumEntries)(NULL, pszPhonebook, (RASENTRYNAME*)pRasEntries, &dwSize, &dwNum);
//
// Check the return code from RasEnumEntries
//
if (ERROR_BUFFER_TOO_SMALL == dwRet) { CMTRACE1(TEXT("RemovePhonebookEntry -- RasEnumEntries said our buffer was too small, New Size=%u"), dwNum*dwStructSize); CmFree(pRasEntries); dwSize = dwStructSize * dwNum; dwNum = 0; } else if (ERROR_SUCCESS == dwRet) { CMTRACE1(TEXT("RemovePhonebookEntry -- RasEnumEntries successful, %u entries enumerated."), dwNum); bExit = TRUE; } else { CMTRACE1(TEXT("RemovePhonebookEntry -- RasEnumEntries Failed, dwRet == %u"), dwRet); goto exit; } } while (!bExit);
//
// At this point we should have entries to process, if not then we will exit here. Otherwise
// we will look for matches and then delete any we find.
//
dwLen = lstrlen(pszEntryName) + 1; // get the length of the Entry Name
bReturn = TRUE; // assume everything is okay at this point.
//
// okay now we are ready to perform the deletions
//
pCurrentRasEntry = pRasEntries; for (dwIdx=0; dwIdx < dwNum; dwIdx++) { CMTRACE2(TEXT("\tRemovePhonebookEntry -- RasEnumEntries returned %s in %s"), pCurrentRasEntry->szEntryName, MYDBGSTR(pszPhonebook));
if (bMatchSimilarEntries) { //
// Match entries that have the first lstrlen(pszEntryName) chars
// the same.
//
lstrcpyn(szTemp, pCurrentRasEntry->szEntryName, dwLen); } else { //
// Only match exact entries.
//
lstrcpy(szTemp, pCurrentRasEntry->szEntryName); }
if (0 == lstrcmp(szTemp, pszEntryName)) { //
// We have an entry that starts with the Long Service Name, so delete it. Note
// that if this is NT5 then we need to clear the szCustomDialDll param of the
// connectoid so we don't get called again on the RasCustomDeleteNotify entry
// point
//
if (plat.IsAtLeastNT5()) { //
// On NT5, we also want to make sure we clean up any credentials associated with this
// connectoid. We do that by calling RasSetCredentials
//
RASCREDENTIALSA RasCreds = {0};
RasCreds.dwSize = sizeof(RASCREDENTIALSA); RasCreds.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain;
dwRet = (pfnSetCredentials)(pszPhonebook, pCurrentRasEntry->szEntryName, &RasCreds, TRUE); // TRUE == fClearCredentials
MYDBGASSERT(ERROR_SUCCESS == dwRet);
RASENTRY_V500 RasEntryV5 = {0};
RasEntryV5.dwSize = sizeof(RASENTRY_V500); RasEntryV5.dwType = RASET_Internet; // RasEntryV5.szCustomDialDll[0] = TEXT('\0'); -- already zero-ed
dwRet = ((pfnSetEntryProperties)(pszPhonebook, pCurrentRasEntry->szEntryName, (RASENTRY*)&RasEntryV5, RasEntryV5.dwSize, NULL, 0)); if (ERROR_SUCCESS != dwRet) { CMTRACE3(TEXT("\t\tRemovePhonebookEntry -- RasSetEntryProperties failed on entry %s in %s, dwRet = %u"), pCurrentRasEntry->szEntryName, MYDBGSTR(pszPhonebook), dwRet); bReturn = FALSE; continue; // don't try to delete the entry it might cause a re-launch problem
} else { CMTRACE2(TEXT("\t\tRemovePhonebookEntry -- Clearing CustomDialDll setting with RasSetEntryProperties on entry %s in %s"), pCurrentRasEntry->szEntryName, MYDBGSTR(pszPhonebook)); } }
dwRet = (pfnDeleteEntry)(pszPhonebook, pCurrentRasEntry->szEntryName); if (ERROR_SUCCESS != dwRet) { CMTRACE3(TEXT("\t\tRemovePhonebookEntry -- RasDeleteEntry failed on entry %s in %s, dwRet = %u"), pCurrentRasEntry->szEntryName, MYDBGSTR(pszPhonebook), dwRet); bReturn = FALSE; // set return to FALSE but continue trying to delete entries
} else { CMTRACE2(TEXT("\t\tRemovePhonebookEntry -- Deleted entry %s in %s"), pCurrentRasEntry->szEntryName, MYDBGSTR(pszPhonebook)); } }
//
// Increment to next RasEntryName struct, note we have to do this manually since
// the sizeof(RASENTRYNAME) is wrong for NT5 structs.
//
pCurrentRasEntry = (RASENTRYNAME*)((BYTE*)pCurrentRasEntry + dwStructSize); }
exit:
CmFree(pRasEntries); return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: DeleteNT5ShortcutFromPathAndName
//
// Synopsis: This function deletes the link specified by the CSIDL (see SHGetSpecialFolderLocation),
// and the profilename. Used before installing a profile to make
// sure we don't get duplicate links.
//
// Arguments: LPCTSTR szProfileName - string that holds the profilename
// int nFolder - the CSIDL identifier of the folder that holds the
// link to delete
//
// Returns: Nothing
//
// History: quintinb Created 5/26/98
//
//+----------------------------------------------------------------------------
void DeleteNT5ShortcutFromPathAndName(HINSTANCE hInstance, LPCTSTR szProfileName, int nFolder) {
TCHAR szFolderDir[MAX_PATH+1];
if (SUCCEEDED(GetNT5FolderPath(nFolder, szFolderDir))) { //
// Now add \Shortcut to %LongServiceName% to the end of path
//
TCHAR szCleanString[MAX_PATH+1]; TCHAR szShortCutPreface[MAX_PATH+1];
ZeroMemory(szCleanString, sizeof(szCleanString)); MYVERIFY(0 != LoadString(hInstance, IDS_SHORTCUT_TO, szShortCutPreface, MAX_PATH)); MYVERIFY(CELEMS(szCleanString) > (UINT)wsprintf(szCleanString, TEXT("%s\\%s %s.lnk"), szFolderDir, szShortCutPreface, szProfileName)); if (SetFileAttributes(szCleanString, FILE_ATTRIBUTE_NORMAL)) { SHFILEOPSTRUCT fOpStruct; ZeroMemory(&fOpStruct, sizeof(fOpStruct)); fOpStruct.wFunc = FO_DELETE; fOpStruct.pFrom = szCleanString; fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
//
// The shell32.dll on Win95 doesn't contain the SHFileOperationW function. Thus if we compile
// this Unicode we must revisit this code and dynamically link to it.
//
MYVERIFY(0 == SHFileOperation(&fOpStruct)); } } }
//+----------------------------------------------------------------------------
//
// Function: CreateNT5ProfileShortcut
//
// Synopsis: This function uses private APIs in NetShell.dll to create a desktop
// shortcut to the specified connections.
//
// Arguments: LPTSTR pszProfileName - Name of the Connection to look for
// LPTSTR pszPhoneBook - Full path to the pbk that the connection resides in
// BOOL bAllUsers - TRUE if looking for an All Users connection
//
// Returns: HRESULT - returns normal hr codes
//
// History: quintinb Created 5/5/98
// quintinb Updated to use Netshell APIs 2/17/99
//
//+----------------------------------------------------------------------------
HRESULT CreateNT5ProfileShortcut(LPCTSTR pszProfileName, LPCTSTR pszPhoneBook, BOOL bAllUsers) {
HRESULT hr = E_FAIL; pfnCreateShortcutSpec pfnCreateShortcut = NULL; pfnRasGetEntryPropertiesSpec pfnGetEntryProperties = NULL;
//
// Check Inputs
//
if ((NULL == pszProfileName) || (TEXT('\0') == pszProfileName[0]) || (NULL != pszPhoneBook && TEXT('\0') == pszPhoneBook[0])) { //
// Then they passed in an invalid string argument, thus return invalid arg. Note
// that pszPhoneBook can be NULL but that if it isn't NULL it cannot be empty.
//
return E_INVALIDARG; }
//
// First Find the GUID of the connection
//
if (!GetRasApis(NULL, NULL, NULL, NULL, &pfnGetEntryProperties, NULL)) { return E_UNEXPECTED; }
DWORD dwRes; DWORD dwSize; LPRASENTRY_V500 pRasEntry = NULL;
pRasEntry = (LPRASENTRY_V500)CmMalloc(sizeof(RASENTRY_V500));
if (NULL != pRasEntry) { ZeroMemory(pRasEntry, sizeof(RASENTRY_V500)); pRasEntry->dwSize = sizeof(RASENTRY_V500); dwSize = sizeof(RASENTRY_V500);
dwRes = (pfnGetEntryProperties)(pszPhoneBook, pszProfileName, (LPRASENTRY)pRasEntry, &dwSize, NULL, NULL); if (0 == dwRes) { //
// Then we were able to get the RasEntry, load the NetShell API
// and call HrCreateShortcut
//
pfnSHGetSpecialFolderPathWSpec pfnSHGetSpecialFolderPathW;
if(GetShell32Apis(NULL, &pfnSHGetSpecialFolderPathW)) { WCHAR szwPath[MAX_PATH+1]; hr = (pfnSHGetSpecialFolderPathW)(NULL, szwPath, bAllUsers ? CSIDL_COMMON_DESKTOPDIRECTORY : CSIDL_DESKTOPDIRECTORY, FALSE);
if (SUCCEEDED(hr) && GetNetShellApis(NULL, &pfnCreateShortcut, NULL)) { hr = (pfnCreateShortcut)(pRasEntry->guidId, szwPath); } } } else { CMTRACE1(TEXT("CreateNT5ProfileShortcut -- RasGetEntryProperties returned %u"), dwRes); CMASSERTMSG(FALSE, TEXT("Unable to find the connection for which the shortcut was requested in the RAS pbk.")); return HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID); } CmFree(pRasEntry); } return hr; }
//+----------------------------------------------------------------------------
//
// Function: WriteCmPhonebookEntry
//
// Synopsis: This function creates an NT5 phonebook entry for a CM connection.
// .
// The function sets:
// - the szAutoDialDll to cmdial32.dll
// - the modem name and device type
// - the type to RASET_Inernet.
//
// Arguments: LPCTSTR szLongServiceName - Name of the Connectoid to be created
// LPCTSTR szFullPathtoPBK - full path to the pbk to put the connectoid in, if NULL
// the system phonebook is used.
// LPCTSTR pszCmsFile - The full path of the referencing .CMS for the profile
//
// Returns: BOOL - TRUE on success
//
// History: 05/05/98 - quintinb - Created Header
// ??/??/?? - henryt - Modified to work on multiple platforms. added modem stuff.
// 01/12/99 - nickball - Replaced fDoDirectConnect with szCmsFile. Handled no modem case.
//
//+----------------------------------------------------------------------------
BOOL WriteCmPhonebookEntry(LPCTSTR szLongServiceName, LPCTSTR szFullPathtoPBK, LPCTSTR pszCmsFile) { pfnRasSetEntryPropertiesSpec pfnSetEntryProperties; DWORD dwRet = 1; CPlatform plat; RASENTRY *pRasEntry = NULL; BOOL bReturn = FALSE; DWORD dwReturn; BOOL fSupportDialup; BOOL fSupportDirect; BOOL fDoDirectConnect; BOOL fSeekVpn; const TCHAR* const c_pszOne = TEXT("1");
MYDBGASSERT(szLongServiceName); MYDBGASSERT(pszCmsFile);
if (NULL == szLongServiceName || NULL == pszCmsFile) { return FALSE; }
CMTRACE2(TEXT("WriteCmPhonebookEntry() - szLongServiceName is %s, szFullPathtoPBK is %s"), szLongServiceName, szFullPathtoPBK ? szFullPathtoPBK : TEXT("<NULL>"));
if (!GetRasApis(NULL, NULL, &pfnSetEntryProperties, NULL, NULL, NULL)) { return FALSE; }
//
// alloc RASENTRY properly
//
if (plat.IsAtLeastNT5()) { RASENTRY_V500 *pRasEntryV500 = (RASENTRY_V500 *)CmMalloc(sizeof(RASENTRY_V500));
if (!pRasEntryV500) { CMTRACE(TEXT("WriteCmPhonebookEntry failed to alloc mem")); goto exit; }
ZeroMemory(pRasEntryV500, sizeof(RASENTRY_V500));
pRasEntryV500->dwSize = sizeof(RASENTRY_V500); pRasEntryV500->dwType = RASET_Internet;
pRasEntry = (RASENTRY *)pRasEntryV500; } else { pRasEntry = (RASENTRY *)CmMalloc(sizeof(RASENTRY));
if (!pRasEntry) { CMTRACE(TEXT("WriteCmPhonebookEntry failed to alloc mem")); goto exit; }
pRasEntry->dwSize = sizeof(RASENTRY); }
//
// Update the RAS entry with our DLL name for AutoDial and CustomDial
// Note: NT5 gets CustomDial only, no AutoDial and AutoDialFunc.
//
if (plat.IsAtLeastNT5()) { //
// Use the machine independent %windir%\system32\cmdial32.dll on NT5
//
lstrcpy(((RASENTRY_V500 *)pRasEntry)->szCustomDialDll, c_pszCmDialPath); } else { TCHAR szSystemDirectory[MAX_PATH+1];
//
// Specify _InetDialHandler@16 as the entry point used for AutoDial.
//
lstrcpy(pRasEntry->szAutodialFunc, c_pszInetDialHandler);
//
// Get the system directory path
//
if (0 == GetSystemDirectory(szSystemDirectory, CELEMS(szSystemDirectory))) { goto exit; }
UINT uCount = (UINT)wsprintf(pRasEntry->szAutodialDll, TEXT("%s\\cmdial32.dll"), szSystemDirectory);
MYDBGASSERT(uCount < CELEMS(pRasEntry->szAutodialDll)); }
if (plat.IsWin9x()) { //
// Win9x requires these to be set
//
pRasEntry->dwFramingProtocol = RASFP_Ppp; pRasEntry->dwCountryID = 1; pRasEntry->dwCountryCode = 1; //lstrcpy(pRasEntry->szAreaCode, TEXT("425"));
lstrcpy(pRasEntry->szLocalPhoneNumber, TEXT("default")); }
//
// Is the profile configured to first use Direct Connect
//
fSupportDialup = GetPrivateProfileInt(c_pszCmSection, c_pszCmEntryDialup, 1, pszCmsFile); fSupportDirect = GetPrivateProfileInt (c_pszCmSection, c_pszCmEntryDirect, 1, pszCmsFile);
fDoDirectConnect = ((fSupportDialup && fSupportDirect && GetPrivateProfileInt(c_pszCmSection, c_pszCmEntryConnectionType, 0, pszCmsFile)) || (!fSupportDialup));
fSeekVpn = fDoDirectConnect;
//
// First try dial-up if appropriate
//
if (!fDoDirectConnect && !PickModem(pRasEntry->szDeviceType, pRasEntry->szDeviceName, FALSE)) { CMTRACE(TEXT("*******Failed to pick a dial-up device!!!!"));
//
// If direct capable, try to find a VPN device
//
fSeekVpn = fSupportDirect; }
//
// If seeking a VPN device
//
if (fSeekVpn) { if (!PickModem(pRasEntry->szDeviceType, pRasEntry->szDeviceName, TRUE)) { CMTRACE(TEXT("*******Failed to pick a VPN device!!!!")); } else { //
// Found VPN device, set default type as appropriate
//
if (!fDoDirectConnect) { CFileNameParts CmsParts(pszCmsFile); TCHAR szCmpFile[MAX_PATH+1];
MYVERIFY(CELEMS(szCmpFile) > (UINT)wsprintf(szCmpFile, TEXT("%s%s"), CmsParts.m_Drive, CmsParts.m_Dir));
szCmpFile[lstrlen(szCmpFile) - 1] = TEXT('\0'); lstrcat(szCmpFile, c_pszCmpExt); WritePrivateProfileString(c_pszCmSection, c_pszCmEntryConnectionType, c_pszOne, szCmpFile); } } }
//
// No device??? Use last resort for dial-up on NT5
//
if (plat.IsAtLeastNT5() && !pRasEntry->szDeviceType[0]) { lstrcpy(pRasEntry->szDeviceType, RASDT_Modem); lstrcpy(pRasEntry->szDeviceName, TEXT("Unavailable device ()"));
CMTRACE2(TEXT("*******Writing szDeviceType - %s and szDeviceName %s"), pRasEntry->szDeviceType, pRasEntry->szDeviceName); }
//
// Zero is the success return value from RasSetEntryProperties
//
dwReturn = ((pfnSetEntryProperties)(szFullPathtoPBK, szLongServiceName, pRasEntry, pRasEntry->dwSize, NULL, 0)); if (ERROR_SUCCESS == dwReturn) { bReturn = TRUE; }
CMTRACE1(TEXT("WriteCmPhonebookEntry() - RasSetEntryProperties failed with error %d"), dwReturn);
exit: CmFree(pRasEntry);
return bReturn; }
//+----------------------------------------------------------------------------
//
// Function: GetRasModems
//
// Synopsis: get a list of modem devices from RAS
//
// Arguments: pprdiRasDevInfo Ras device info list
// pdwCnt modem count
//
// Returns: TRUE, if a list is obtained
//
//+----------------------------------------------------------------------------
BOOL GetRasModems( LPRASDEVINFO *pprdiRasDevInfo, LPDWORD pdwCnt ) { DWORD dwLen; DWORD dwRes; DWORD dwCnt; pfnRasEnumDevicesSpec pfnEnumDevices;
if (pprdiRasDevInfo) { *pprdiRasDevInfo = NULL; } if (pdwCnt) { *pdwCnt = 0; } if (!GetRasApis(NULL, NULL, NULL, &pfnEnumDevices, NULL, NULL)) { return FALSE; }
dwLen = 0; dwRes = pfnEnumDevices(NULL, &dwLen, &dwCnt); CMTRACE3(TEXT("GetRasModems() RasEnumDevices(NULL,pdwLen,&dwCnt) returns %u, dwLen=%u, dwCnt=%u."), dwRes, dwLen, dwCnt); if ((dwRes != ERROR_SUCCESS) && (dwRes != ERROR_BUFFER_TOO_SMALL) || (dwLen < sizeof(**pprdiRasDevInfo))) { return FALSE; } *pprdiRasDevInfo = (LPRASDEVINFO) CmMalloc(__max(dwLen, sizeof(**pprdiRasDevInfo)));
if (*pprdiRasDevInfo) { (*pprdiRasDevInfo)->dwSize = sizeof(**pprdiRasDevInfo);
dwRes = pfnEnumDevices(*pprdiRasDevInfo, &dwLen, &dwCnt); CMTRACE3(TEXT("GetRasModems() RasEnumDevices(NULL,pdwLen,&dwCnt) returns %u, dwLen=%u, dwCnt=%u."), dwRes, dwLen, dwCnt); if (dwRes != ERROR_SUCCESS) { CmFree(*pprdiRasDevInfo); *pprdiRasDevInfo = NULL; return FALSE; } if (pdwCnt) { *pdwCnt = dwCnt; } } else { CMASSERTMSG(FALSE, TEXT("GetRasModems -- CmMalloc returned a NULL pointer for *pprdiRasDevInfo.")); return FALSE; }
return TRUE; }
//+----------------------------------------------------------------------------
//
// Function: PickModem
//
// Synopsis: Pick a default modem
//
// Arguments: OUT pszDeviceType, the device type if not NULL
// OUT pszDeviceName, the device name if not NULL
// OUT fUseVpnDevice Use VPN device or not
//
// Returns: TRUE, is modem is found
//
//+----------------------------------------------------------------------------
BOOL PickModem( LPTSTR pszDeviceType, LPTSTR pszDeviceName, BOOL fUseVpnDevice ) { LPRASDEVINFO prdiModems; DWORD dwCnt; DWORD dwIdx;
//
// First, get a list of modems from RAS
//
if (!GetRasModems(&prdiModems, &dwCnt) || dwCnt == 0) { return FALSE; }
//
// find the first device and use it by default.
// Use VPN device if it's a VPN connection.
//
for (dwIdx=0; dwIdx<dwCnt; dwIdx++) { if (fUseVpnDevice && !lstrcmpi(prdiModems[dwIdx].szDeviceType, RASDT_Vpn) || !fUseVpnDevice && (!lstrcmpi(prdiModems[dwIdx].szDeviceType, RASDT_Isdn) || !lstrcmpi(prdiModems[dwIdx].szDeviceType, RASDT_Modem))) { break; } }
//
// If we have a match, fill device name and device type
//
if (dwIdx < dwCnt) { if (pszDeviceType) { lstrcpy(pszDeviceType, prdiModems[dwIdx].szDeviceType); } if (pszDeviceName) { lstrcpy(pszDeviceName, prdiModems[dwIdx].szDeviceName); } }
CmFree(prdiModems);
return (dwIdx < dwCnt); }
//+----------------------------------------------------------------------------
//
// Function: IsMemberOfGroup
//
// Synopsis: This function return TRUE if the current user is a member of
// the passed and FALSE passed in Group RID.
//
// Arguments: DWORD dwGroupRID -- the RID of the group to check membership of
// BOOL bUseBuiltinDomainRid -- whether the SECURITY_BUILTIN_DOMAIN_RID
// RID should be used to build the Group
// SID
//
// Returns: BOOL - TRUE if the user is a member of the specified group
//
// History: quintinb Shamelessly stolen from MSDN 02/19/98
// quintinb Reworked and renamed 06/18/99
// to apply to more than just Admins
// quintinb Rewrote to use CheckTokenMemberShip 08/18/99
// since the MSDN method was no longer
// correct on NT5 -- 389229
//
//+----------------------------------------------------------------------------
BOOL IsMemberOfGroup(DWORD dwGroupRID, BOOL bUseBuiltinDomainRid) { CPlatform cmplat; PSID psidGroup = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; BOOL bSuccess = FALSE;
if (FALSE == cmplat.IsAtLeastNT5()) { CMASSERTMSG(FALSE, TEXT("IsMemberOfGroup -- Trying to use an NT5 only function on a downlevel platform.")); return FALSE; }
//
// Make a SID for the Group we are checking for, Note that we if we need the Built
// in Domain RID (for Groups like Administrators, PowerUsers, Users, etc)
// then we will have two entries to pass to AllocateAndInitializeSid. Otherwise,
// (for groups like Authenticated Users) we will only have one.
//
BYTE byNum; DWORD dwFirstRID; DWORD dwSecondRID;
if (bUseBuiltinDomainRid) { byNum = 2; dwFirstRID = SECURITY_BUILTIN_DOMAIN_RID; dwSecondRID = dwGroupRID; } else { byNum = 1; dwFirstRID = dwGroupRID; dwSecondRID = 0; }
if (AllocateAndInitializeSid(&siaNtAuthority, byNum, dwFirstRID, dwSecondRID, 0, 0, 0, 0, 0, 0, &psidGroup))
{ //
// Now we need to dynamically load the CheckTokenMemberShip API from
// advapi32.dll since it is a Win2k only API.
//
HMODULE hAdvapi = GetModuleHandle(TEXT("advapi32.dll")); if (hAdvapi) { typedef BOOL (WINAPI *pfnCheckTokenMembershipSpec)(HANDLE, PSID, PBOOL); pfnCheckTokenMembershipSpec pfnCheckTokenMembership;
pfnCheckTokenMembership = (pfnCheckTokenMembershipSpec)GetProcAddress(hAdvapi, "CheckTokenMembership");
if (pfnCheckTokenMembership) { //
// Check to see if the user is actually a member of the group in question
//
if (!(pfnCheckTokenMembership)(NULL, psidGroup, &bSuccess)) { bSuccess = FALSE; CMASSERTMSG(FALSE, TEXT("CheckTokenMemberShip Failed.")); } } else { CMASSERTMSG(FALSE, TEXT("IsMemberOfGroup -- GetProcAddress failed for CheckTokenMemberShip")); } } else { CMASSERTMSG(FALSE, TEXT("IsMemberOfGroup -- Unable to get the module handle for advapi32.dll")); }
FreeSid (psidGroup); } return bSuccess; }
//+----------------------------------------------------------------------------
//
// Function: IsAdmin
//
// Synopsis: Check to see if the user is a member of the Administrators group
// or not.
//
// Arguments: None
//
// Returns: BOOL - TRUE if the current user is an Administrator
//
// History: quintinb Created Header 8/18/99
//
//+----------------------------------------------------------------------------
BOOL IsAdmin(void) { return IsMemberOfGroup(DOMAIN_ALIAS_RID_ADMINS, TRUE); // TRUE == bUseBuiltinDomainRid
}
//+----------------------------------------------------------------------------
//
// Function: IsAuthenticatedUser
//
// Synopsis: Check to see if the current user is a member of the
// Authenticated Users group.
//
// Arguments: None
//
// Returns: BOOL - TRUE if the current user is a member of the
// Authenticated Users group.
//
// History: quintinb Created Header 8/18/99
//
//+----------------------------------------------------------------------------
BOOL IsAuthenticatedUser(void) { return IsMemberOfGroup(SECURITY_AUTHENTICATED_USER_RID, FALSE); // FALSE == bUseBuiltinDomainRid
}
//+----------------------------------------------------------------------------
//
// Function: GetNT5FolderPath
//
// Synopsis: Get the folder path on NT5
// Since cmstp.exe is launched in netman by CreateProcessAsUser
// SHGetSpecialFolderPath does not work. We have to call
// SHGetFolderPath with an access token.
//
// Arguments: int nFolder - Value specifying the folder for which to retrieve
// the location.
// OUT LPTSTR lpszPath - Address of a character buffer that receives
// the drive and path of the specified folder. This
// buffer must be at least MAX_PATH characters in size.
//
// Returns: HRESULT -
//
// History: fengsun Created Header 6/18/98
// quintinb modified to use GetShell32Apis 11-22-98
//
//+----------------------------------------------------------------------------
HRESULT GetNT5FolderPath(int nFolder, OUT LPTSTR lpszPath) { MYDBGASSERT(lpszPath); pfnSHGetFolderPathSpec pfnSHGetFolderPath;
//
// Call shell32.dll-->SHGetFolderPath, which takes a token.
//
if(!GetShell32Apis(&pfnSHGetFolderPath, NULL)) { CMASSERTMSG(FALSE, TEXT("Failed to load shell32.dll or ShGetFolderPath")); return E_UNEXPECTED; }
//
// Get the current process token
//
HANDLE hToken; // The token of the process, to be passed to SHGetFolderPath
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { CMASSERTMSG(FALSE, TEXT("OpenThreadToken failed")); return E_UNEXPECTED; }
HRESULT hr = pfnSHGetFolderPath(NULL, nFolder, hToken, 0, lpszPath);
MYVERIFY(0 != CloseHandle(hToken));
return hr; }
//+----------------------------------------------------------------------------
//
// Function: HrIsCMProfilePrivate
//
// Synopsis: This function compares the inputed file path with the application
// data path of the system. If the file path contains the app data
// path then it is considered to be a private profile.
//
// Arguments: LPTSTR szFilePath - directory or file path to compare against
//
// Returns: HRESULT - S_OK if a private profile, S_FALSE if it is an all users
// profile. Standard error codes otherwise.
//
// History: quintinb original code
//
//+----------------------------------------------------------------------------
HRESULT HrIsCMProfilePrivate(LPCTSTR szFilePath) { UINT uiLen; TCHAR szAppDataDir[MAX_PATH+1]; TCHAR szTemp[MAX_PATH+1] = {TEXT("")}; CPlatform plat;
if ((NULL == szFilePath) || (TEXT('\0') == szFilePath[0])) { return E_POINTER; }
//
// Can't be a private user profile unless we are on NT5
//
if (!(plat.IsAtLeastNT5())) { return S_FALSE; }
//
// Figure out what the user directory of the current user is. We can compare this
// against the directory of the phonebook and see if we have a private user
// profile or an all user profile.
if (FAILED(GetNT5FolderPath(CSIDL_APPDATA, szAppDataDir))) { return E_UNEXPECTED; }
uiLen = lstrlen(szAppDataDir) + 1; lstrcpyn(szTemp, szFilePath, uiLen);
if ((NULL != szTemp) && (0 == lstrcmpi(szAppDataDir, szTemp))) { return S_OK; } else { return S_FALSE; } }
//+----------------------------------------------------------------------------
//
// Function: RefreshDesktop
//
// Synopsis: This function refreshes the desktop and basically takes the place
// of showicon.exe (in fact the code is a cut and paste from the
// main of showicon).
//
// Arguments: None
//
// Returns: Nothing
//
// History: quintinb Created Header 5/5/98
//
//+----------------------------------------------------------------------------
void RefreshDesktop() { LPMALLOC pMalloc = NULL; LPITEMIDLIST pItemIDList = NULL;
//
// Get the IMalloc for the Shell.
//
HRESULT hr = SHGetMalloc(&pMalloc); if (SUCCEEDED(hr)) { // Get the desktop ID list..
hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pItemIDList); if (SUCCEEDED(hr)) { // Notify of change.
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, (LPCVOID)pItemIDList, NULL);
pMalloc->Free(pItemIDList); } MYVERIFY(SUCCEEDED(pMalloc->Release())); } }
//+----------------------------------------------------------------------------
//
// Function: GetPrivateCmUserDir
//
// Synopsis: This function fills in the string passed in with the path to the
// path where CM should be installed. For instance, it should return
// c:\users\quintinb\Application Data\Microsoft\Network\Connection Manager
// for me. Please note that this function is NT5 only.
//
// Arguments: LPTSTR pszDir - String to the Users Connection Manager Directory
//
// Returns: LPTSTR - String to the Users Connection Manager Directory
//
// History: quintinb Created Header 2/19/98
//
//+----------------------------------------------------------------------------
LPTSTR GetPrivateCmUserDir(LPTSTR pszDir, HINSTANCE hInstance) { LPITEMIDLIST pidl; LPMALLOC pMalloc; CPlatform plat; TCHAR szTemp[MAX_PATH+1];
MYDBGASSERT(pszDir); pszDir[0] = TEXT('\0');
if (!plat.IsAtLeastNT5()) { CMASSERTMSG(FALSE, TEXT("GetPrivateCmUserDir -- This NT5 only function was called from a different platform.")); goto exit; }
if (FAILED(GetNT5FolderPath(CSIDL_APPDATA, pszDir))) { goto exit; }
MYVERIFY(0 != LoadString(hInstance, IDS_CMSUBFOLDER, szTemp, MAX_PATH)); MYVERIFY(NULL != lstrcat(pszDir, szTemp));
exit: return pszDir; }
//+----------------------------------------------------------------------------
//
// Function: LaunchProfile
//
// Synopsis: This function handles launching the CM profile (NTRAID 201307) after
// installation. On NT5 it opens the connfolder and launches the
// correct connection by doing a shell execute on the pidl we get from
// enumerating the connections folder. On down level we use Cmmgr32.exe
// and the full path to the cmp file. Please note that on downlevel we
// only care about the input param pszFullPathToCmpFile, while on NT5
// we only care about pszwServiceName and bInstallForAllUsers.
//
// Arguments: LPCTSTR pszFullPathToCmpFile - the full path to the cmp file (used on legacy only)
// LPCSTR pszServiceName - the Long Service Name
// BOOL bInstallForAllUsers -
//
// Returns: HRESULT -- standard COM error codes
//
// History: quintinb Created 11/16/98
//
//+----------------------------------------------------------------------------
HRESULT LaunchProfile(LPCTSTR pszFullPathToCmpFile, LPCTSTR pszServiceName, LPCTSTR pszPhoneBook, BOOL bInstallForAllUsers) { CPlatform plat; HRESULT hr = E_FAIL;
if ((NULL == pszFullPathToCmpFile) || (NULL == pszServiceName) || (NULL != pszPhoneBook && TEXT('\0') == pszPhoneBook[0])) { CMASSERTMSG(FALSE, TEXT("Invalid argument passed to LaunchProfile")); return E_INVALIDARG; }
if (plat.IsAtLeastNT5()) { CMASSERTMSG((TEXT('\0') != pszServiceName), TEXT("Empty ServiceName passed to LaunchProfile on win2k.")); pfnRasGetEntryPropertiesSpec pfnGetEntryProperties = NULL;
if (!GetRasApis(NULL, NULL, NULL, NULL, &pfnGetEntryProperties, NULL)) { return E_UNEXPECTED; }
DWORD dwRes; DWORD dwSize; LPRASENTRY_V500 pRasEntry = NULL;
pRasEntry = (LPRASENTRY_V500)CmMalloc(sizeof(RASENTRY_V500));
if (NULL != pRasEntry) { ZeroMemory(pRasEntry, sizeof(RASENTRY_V500)); pRasEntry->dwSize = sizeof(RASENTRY_V500); dwSize = sizeof(RASENTRY_V500);
dwRes = (pfnGetEntryProperties)(pszPhoneBook, pszServiceName, (LPRASENTRY)pRasEntry, &dwSize, NULL, NULL); if (0 == dwRes) { //
// Then we were able to get the RasEntry, load the NetShell API
// and call HrCreateShortcut
//
if (plat.IsAtLeastNT51()) { pfnLaunchConnectionExSpec pfnLaunchConnectionEx = NULL;
if (GetNetShellApis(NULL, NULL, &pfnLaunchConnectionEx)) { //
// Launch Connections Folder and Connection together
//
DWORD dwFlags = 0x1; // 0x1 => Opens the folder before launching the connection
hr = (pfnLaunchConnectionEx)(dwFlags, pRasEntry->guidId); MYVERIFY(SUCCEEDED(hr)); } } else { pfnLaunchConnectionSpec pfnLaunchConnection = NULL;
if (GetNetShellApis(&pfnLaunchConnection, NULL, NULL)) { //
// Now Launch the Connections Folder
//
CLoadConnFolder Connections; Connections.HrLaunchConnFolder();
//
// Finally Launch the Connection
//
hr = (pfnLaunchConnection)(pRasEntry->guidId); MYVERIFY(SUCCEEDED(hr)); } } } else { CMTRACE1(TEXT("LaunchProfile -- RasGetEntryProperties returned %u"), dwRes); CMASSERTMSG(FALSE, TEXT("Unable to find the connection that we are supposed to launch in the RAS pbk.")); return HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID); } CmFree(pRasEntry); } } else { SHELLEXECUTEINFO sei;
if ((NULL != pszFullPathToCmpFile) && (TEXT('\0') != pszFullPathToCmpFile)) { TCHAR szCmmgrPath[MAX_PATH+1]; TCHAR szSystemDir[MAX_PATH+1]; TCHAR szCmp[MAX_PATH+1]; ZeroMemory(&szCmp, sizeof(szCmp)); ZeroMemory(&szCmmgrPath, sizeof(szCmmgrPath)); ZeroMemory(&szSystemDir, sizeof(szSystemDir));
lstrcpy(szCmp, TEXT("\"")); lstrcat(szCmp, pszFullPathToCmpFile); lstrcat(szCmp, TEXT("\""));
UINT uRet = GetSystemDirectory(szSystemDir, MAX_PATH); if ((0 == uRet) || (MAX_PATH < uRet)) { //
// Give up, not the end of the world not to launch the profile
//
return E_UNEXPECTED; } else { wsprintf(szCmmgrPath, TEXT("%s\\cmmgr32.exe"), szSystemDir); }
ZeroMemory(&sei, sizeof(sei)); sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI; sei.nShow = SW_SHOWNORMAL; sei.lpFile = szCmmgrPath; sei.lpParameters = szCmp; sei.lpDirectory = szSystemDir;
if (!ShellExecuteEx(&sei)) { CMASSERTMSG(FALSE, TEXT("Unable to launch installed connection!")); } else { hr = S_OK; } } } return hr; }
//+----------------------------------------------------------------------------
//
// Function: AllUserProfilesInstalled
//
// Synopsis: Checks if any profiles are listed in the HKLM Mappings key.
//
// Arguments: None
//
// Returns: BOOL - TRUE if mappings values exist in the HKLM mappings key
//
// History: quintinb Created Header 11/1/98
//
//+----------------------------------------------------------------------------
BOOL AllUserProfilesInstalled() { BOOL bReturn = FALSE; HKEY hKey; DWORD dwNumValues;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_pszRegCmMappings, 0, KEY_READ, &hKey)) { if ((ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumValues, NULL, NULL, NULL, NULL)) && (dwNumValues > 0)) { //
// Then we have mappings values
//
bReturn = TRUE;
} RegCloseKey(hKey); }
return bReturn; }
//+----------------------------------------------------------------------------
//
// Function: GetProcAddressFromRasApi32orRnaph
//
// Synopsis: A helper function to first look in RasApi32.dll (using the global
// dll class pointer) and then check in Rnaph.dll if the required
// function was not found.
//
// Arguments: LPTSTR pszFunc - String of the function to look for
// CPlatform* pPlat - a CPlatform class pointer to prevent creating
// and destructing a new one everytime this is called.
//
// Returns: LPVOID - NULL if the function wasn't found, a pFunc otherwise.
//
// History: quintinb Created 11/23/98
//
//+----------------------------------------------------------------------------
LPVOID GetProcAddressFromRasApi32orRnaph(LPCSTR pszFunc, CPlatform* pPlat) { LPVOID pFunc; MYDBGASSERT(g_pRasApi32);
pFunc = g_pRasApi32->GetProcAddress(pszFunc); if (NULL == pFunc) { //
// On win95 gold check rnaph
//
if (pPlat->IsWin95Gold()) { if (NULL == g_pRnaph) { g_pRnaph = (CDynamicLibrary*)CmMalloc(sizeof(CDynamicLibrary)); if (NULL == g_pRnaph) { return FALSE; } }
if (!(g_pRnaph->IsLoaded())) { g_pRnaph->Load(TEXT("rnaph.dll")); }
pFunc = g_pRnaph->GetProcAddress(pszFunc); } } return pFunc; }
//+----------------------------------------------------------------------------
//
// Function: GetNetShellApis
//
// Synopsis: This is a wrapper function to access the private Netshell api's that allow
// cmstp.exe to interact with the Connections folder on Windows 2000.
// This function caches the Netshell function pointers as they are
// accessed for later use. NULL can be passed if a function isn't required.
//
// Arguments: pfnLaunchConnectionSpec* pLaunchConnection - var to hold function pointer
// pfnCreateShortcutSpec* pCreateShortcut - var to hold function pointer
// pfnLaunchConnectionEx pLaunchConnectionEx - var to hold function pointer
//
// Returns: BOOL - TRUE if all required APIs were retrieved
//
// History: quintinb Created 2/17/99
//
//+----------------------------------------------------------------------------
BOOL GetNetShellApis(pfnLaunchConnectionSpec* pLaunchConnection, pfnCreateShortcutSpec* pCreateShortcut, pfnLaunchConnectionExSpec* pLaunchConnectionEx) { CPlatform plat; static pfnLaunchConnectionSpec pfnLaunchConnection = NULL; static pfnCreateShortcutSpec pfnCreateShortcut = NULL; static pfnLaunchConnectionExSpec pfnLaunchConnectionEx = NULL;
if (!(plat.IsAtLeastNT5())) { //
// These functions are only used on NT5. Return FALSE otherwise.
//
CMASSERTMSG(FALSE, TEXT("Trying to use NetShell Private Api's on platforms other than Windows 2000.")); return FALSE; }
if (NULL == g_pNetShell) { g_pNetShell = (CDynamicLibrary*)CmMalloc(sizeof(CDynamicLibrary)); if (NULL == g_pNetShell) { return FALSE; } }
if (!(g_pNetShell->IsLoaded())) { g_pNetShell->Load(TEXT("netshell.dll")); } if (NULL != pLaunchConnection) { if (pfnLaunchConnection) { *pLaunchConnection = pfnLaunchConnection; } else { *pLaunchConnection = (pfnLaunchConnectionSpec)g_pNetShell->GetProcAddress("HrLaunchConnection"); if (NULL == *pLaunchConnection) { return FALSE; } else { pfnLaunchConnection = *pLaunchConnection; } } }
if (NULL != pCreateShortcut) { if (pfnCreateShortcut) { *pCreateShortcut = pfnCreateShortcut; } else { *pCreateShortcut = (pfnCreateShortcutSpec)g_pNetShell->GetProcAddress("HrCreateDesktopIcon"); if (NULL == *pCreateShortcut) { return FALSE; } else { pfnCreateShortcut = *pCreateShortcut; } } }
if (NULL != pLaunchConnectionEx) { if (pfnLaunchConnectionEx) { *pLaunchConnectionEx = pfnLaunchConnectionEx; } else { if (!(plat.IsAtLeastNT51())) { return FALSE; } else { *pLaunchConnectionEx = (pfnLaunchConnectionExSpec)g_pNetShell->GetProcAddress("HrLaunchConnectionEx"); if (NULL == *pLaunchConnectionEx) { return FALSE; } else { pfnLaunchConnectionEx = *pLaunchConnectionEx; } } } }
return TRUE; }
//+----------------------------------------------------------------------------
//
// Function: GetRasApis
//
// Synopsis: This is a wrapper function to access the RasApis that cmstp.exe uses.
// This function caches the RAS api function pointers as they are
// accessed for later use. NULL can be passed if a function isn't required.
//
// Arguments: pfnRasDeleteEntrySpec* pRasDeleteEntry - var to hold func pointer
// pfnRasEnumEntriesSpec* pRasEnumEntries - var to hold func pointer
// pfnRasSetEntryPropertiesSpec* pRasSetEntryProperties - var to hold func pointer
// pfnRasEnumDevicesSpec* pRasEnumDevices - var to hold func pointer
// pfnRasSetCredentialsSpec* pRasSetCredentials - var to hold func pointer
//
// Returns: BOOL - TRUE if all required APIs were retrieved
//
// History: quintinb Created 11/23/98
//
//+----------------------------------------------------------------------------
BOOL GetRasApis(pfnRasDeleteEntrySpec* pRasDeleteEntry, pfnRasEnumEntriesSpec* pRasEnumEntries, pfnRasSetEntryPropertiesSpec* pRasSetEntryProperties, pfnRasEnumDevicesSpec* pRasEnumDevices, pfnRasGetEntryPropertiesSpec* pRasGetEntryProperties, pfnRasSetCredentialsSpec* pRasSetCredentials) { CPlatform plat; static pfnRasDeleteEntrySpec pfnRasDeleteEntry = NULL; static pfnRasEnumEntriesSpec pfnRasEnumEntries = NULL; static pfnRasSetEntryPropertiesSpec pfnRasSetEntryProperties = NULL; static pfnRasEnumDevicesSpec pfnRasEnumDevices = NULL; static pfnRasGetEntryPropertiesSpec pfnRasGetEntryProperties = NULL; static pfnRasSetCredentialsSpec pfnRasSetCredentials = NULL;
if (NULL == g_pRasApi32) { g_pRasApi32 = (CDynamicLibrary*)CmMalloc(sizeof(CDynamicLibrary)); if (NULL == g_pRasApi32) { return FALSE; } }
if (!(g_pRasApi32->IsLoaded())) { g_pRasApi32->Load(TEXT("rasapi32.dll")); } if (NULL != pRasDeleteEntry) { if (pfnRasDeleteEntry) { *pRasDeleteEntry = pfnRasDeleteEntry; } else { *pRasDeleteEntry = (pfnRasDeleteEntrySpec)GetProcAddressFromRasApi32orRnaph("RasDeleteEntryA", &plat); if (NULL == *pRasDeleteEntry) { return FALSE; } else { pfnRasDeleteEntry = *pRasDeleteEntry; } } }
if (NULL != pRasEnumEntries) { if (pfnRasEnumEntries) { *pRasEnumEntries = pfnRasEnumEntries; } else { *pRasEnumEntries = (pfnRasEnumEntriesSpec)g_pRasApi32->GetProcAddress("RasEnumEntriesA");
if (NULL == *pRasEnumEntries) { //
// A required Function couldn't be loaded
//
return FALSE; } else { pfnRasEnumEntries = *pRasEnumEntries; } } }
if (NULL != pRasSetEntryProperties) { if (pfnRasSetEntryProperties) { *pRasSetEntryProperties = pfnRasSetEntryProperties; } else { *pRasSetEntryProperties = (pfnRasSetEntryPropertiesSpec)GetProcAddressFromRasApi32orRnaph("RasSetEntryPropertiesA", &plat); if (NULL == *pRasSetEntryProperties) { return FALSE; } else { pfnRasSetEntryProperties = *pRasSetEntryProperties; } } }
if (NULL != pRasEnumDevices) { if (pfnRasEnumDevices) { *pRasEnumDevices = pfnRasEnumDevices; } else { *pRasEnumDevices = (pfnRasEnumDevicesSpec)GetProcAddressFromRasApi32orRnaph("RasEnumDevicesA", &plat); if (NULL == *pRasEnumDevices) { return FALSE; } else { pfnRasEnumDevices = *pRasEnumDevices; } } }
if (NULL != pRasGetEntryProperties) { if (pfnRasGetEntryProperties) { *pRasGetEntryProperties = pfnRasGetEntryProperties; } else { *pRasGetEntryProperties = (pfnRasGetEntryPropertiesSpec)GetProcAddressFromRasApi32orRnaph("RasGetEntryPropertiesA", &plat); if (NULL == *pRasGetEntryProperties) { return FALSE; } else { pfnRasGetEntryProperties = *pRasGetEntryProperties; } } }
if (NULL != pRasSetCredentials) { if (pfnRasSetCredentials) { *pRasSetCredentials = pfnRasSetCredentials; } else { *pRasSetCredentials = (pfnRasSetCredentialsSpec)GetProcAddressFromRasApi32orRnaph("RasSetCredentialsA", &plat); if (NULL == *pRasSetCredentials) { return FALSE; } else { pfnRasSetCredentials = *pRasSetCredentials; } } }
return TRUE; }
//+----------------------------------------------------------------------------
//
// Function: GetShell32Apis
//
// Synopsis: This function is used to load the shell32.dll and call getprocaddress
// on the needed functions. This function is used to speed up the process
// by keeping one copy of shell32.dll in memory and caching the function
// pointers requested. If a function pointer hasn't been requested yet,
// then it will have to be looked up.
//
// Arguments: pfnSHGetFolderPathSpec* pGetFolderPath - pointer for SHGetFolderPath
// pfnSHGetSpecialFolderPathWSpec* pGetSpecialFolderPathW - pointer for GetSpecialFolderPathW
//
// Returns: BOOL - TRUE if all requested function pointers were retreived.
//
// History: quintinb Created 11/23/98
//
//+----------------------------------------------------------------------------
BOOL GetShell32Apis(pfnSHGetFolderPathSpec* pGetFolderPath, pfnSHGetSpecialFolderPathWSpec* pGetSpecialFolderPathW) { static pfnSHGetFolderPathSpec pfnSHGetFolderPath = NULL; // this takes a User token
static pfnSHGetSpecialFolderPathWSpec pfnSHGetSpecialFolderPathW = NULL;
#ifdef UNICODE
const CHAR c_pszSHGetFolderPath[] = "SHGetFolderPathW"; #else
const CHAR c_pszSHGetFolderPath[] = "SHGetFolderPathA"; #endif
const CHAR c_pszSHGetSpecialFolderPathW[] = "SHGetSpecialFolderPathW";
if (NULL == g_pShell32) { g_pShell32 = (CDynamicLibrary*)CmMalloc(sizeof(CDynamicLibrary)); if (NULL == g_pShell32) { return FALSE; } }
if (!(g_pShell32->IsLoaded())) { if(!g_pShell32->Load(TEXT("shell32.dll"))) { return FALSE; } }
if (NULL != pGetFolderPath) { if (pfnSHGetFolderPath) { *pGetFolderPath = pfnSHGetFolderPath; } else { *pGetFolderPath = (pfnSHGetFolderPathSpec)g_pShell32->GetProcAddress(c_pszSHGetFolderPath); if (NULL == *pGetFolderPath) { return FALSE; } else { pfnSHGetFolderPath = *pGetFolderPath; } } }
if (NULL != pGetSpecialFolderPathW) { if (pfnSHGetSpecialFolderPathW) { *pGetSpecialFolderPathW = pfnSHGetSpecialFolderPathW; } else { *pGetSpecialFolderPathW = (pfnSHGetSpecialFolderPathWSpec)g_pShell32->GetProcAddress(c_pszSHGetSpecialFolderPathW); if (NULL == *pGetSpecialFolderPathW) { return FALSE; } else { pfnSHGetSpecialFolderPathW = *pGetSpecialFolderPathW; } } }
return TRUE; }
|