//+---------------------------------------------------------------------------- // // 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 "linkdll.cpp" #include "allowaccess.cpp" #include "getpbk.cpp" // // For GetAllUsersCmDir // #include "allcmdir.cpp" // // Need the definition for CM_PBK_FILTER_PREFIX // #include "cmdefs.h" // // Include the SafeNet detection code... note that // cmstp doesn't include the UAPI and thus requires // a fixup for RegOpenKeyExU // #ifndef RegOpenKeyExU #ifdef UNICODE #define RegOpenKeyExU RegOpenKeyExW #else #define RegOpenKeyExU RegOpenKeyExA #endif #endif #ifndef RegQueryValueExU #ifdef UNICODE #define RegQueryValueExU RegQueryValueExW #else #define RegQueryValueExU RegQueryValueExA #endif #endif #ifndef lstrcatU #ifdef UNICODE #define lstrcatU lstrcatW #else #define lstrcatU lstrcatA #endif #endif #ifndef lstrlenU #ifdef UNICODE #define lstrlenU lstrlenW #else #define lstrlenU lstrlenA #endif #endif #include "cmsafenet.cpp" // // Include the Connections folder specific headers // //#include "shlobjp.h" //#include // needed for initing guids //#include // DON'T CHANGE the ORDER of these header files unless you know what you are doing //#include // IID_IDataObject //#include // 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 pszInstallDir, LPTSTR* ppszPhonebook) { // // Decided to fix this function so that it correctly returns the hidden phonebook path. // Most of this code is taken from GetPhoneBookPath. We needed to fix this functions // so that we can delete (local & global) Internet credentials. // This file is now named _CMPhone (no .pbk extension) and is now located in the same directory // as the rasphone.pbk file on NT4, Win2K, and WinXP. Note that this function isn't // used on Win9x or NT4. // BOOL bReturn = FALSE; if (NULL == ppszPhonebook) { CMASSERTMSG(FALSE, TEXT("GetHiddenPhoneBookPath -- Invalid Parameter")); return FALSE; } CPlatform plat; if (plat.IsAtLeastNT5()) { if ((NULL == pszInstallDir) || (TEXT('\0') == pszInstallDir[0])) { CMASSERTMSG(FALSE, TEXT("GetHiddenPhoneBookPath -- Invalid Install Dir parameter.")); return FALSE; } // // Now Create the path to the phonebook. // LPTSTR pszPhonebook; TCHAR szInstallDir[MAX_PATH+1]; ZeroMemory(szInstallDir, CELEMS(szInstallDir)); if (TEXT('\\') == pszInstallDir[lstrlen(pszInstallDir) - 1]) { // // Then the path ends in a backslash. Thus we won't properly // remove CM from the path. Remove the backslash. // lstrcpyn(szInstallDir, pszInstallDir, min(lstrlen(pszInstallDir), MAX_PATH)); } else { lstrcpy(szInstallDir, pszInstallDir); } CFileNameParts InstallDirPath(szInstallDir); pszPhonebook = (LPTSTR)CmMalloc(lstrlen(InstallDirPath.m_Drive) + lstrlen(InstallDirPath.m_Dir) + lstrlen(c_pszPbk) + lstrlen(c_pszRasHiddenPhonePbk) + 1); if (NULL != pszPhonebook) { wsprintf(pszPhonebook, TEXT("%s%s%s"), InstallDirPath.m_Drive, InstallDirPath.m_Dir, c_pszPbk); // // Use CreateLayerDirectory to recursively create the directory structure as // necessary (will create all the directories in a full path if necessary). // MYVERIFY(FALSE != CreateLayerDirectory(pszPhonebook)); MYVERIFY(NULL != lstrcat(pszPhonebook, c_pszRasHiddenPhonePbk)); HANDLE hPbk = CreateFile(pszPhonebook, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // // If we get an invalid handle that's ok. We still have the path and should try to // remove the credentials. So no need to return FALSE // if (hPbk != INVALID_HANDLE_VALUE) { MYVERIFY(0 != CloseHandle(hPbk)); } *ppszPhonebook = pszPhonebook; bReturn = TRUE; } else { CMASSERTMSG(FALSE, TEXT("CmMalloc returned NULL")); return FALSE; } } else { *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("")); 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; dwIdxSHGetFolderPath, 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]={0}; TCHAR szSystemDir[MAX_PATH+1]={0}; TCHAR szCmp[MAX_PATH+1]={0}; 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; }