2016 lines
63 KiB
C++
2016 lines
63 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|