You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1279 lines
39 KiB
1279 lines
39 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: ActList.cpp
|
|
//
|
|
// Module: CMDIAL32.DLL
|
|
//
|
|
// Synopsis: Implement the two connect action list class
|
|
// CAction and CActionList
|
|
//
|
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
//
|
|
// Author: fengsun Created 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
#include "cmmaster.h"
|
|
#include "ActList.h"
|
|
#include "stp_str.h"
|
|
|
|
//
|
|
// Include the custom action parsing routine that CM and CMAK now share, HrParseCustomActionString
|
|
//
|
|
#include "parseca.cpp"
|
|
|
|
//
|
|
// Constructor and destructor
|
|
//
|
|
|
|
CActionList::CActionList()
|
|
{
|
|
m_pActionList = NULL;
|
|
m_nNum = 0;
|
|
m_nSize = 0;
|
|
m_pszType = NULL;
|
|
}
|
|
|
|
CActionList::~CActionList()
|
|
{
|
|
for (UINT i = 0; i < m_nNum; i++)
|
|
{
|
|
delete m_pActionList[i];
|
|
}
|
|
|
|
CmFree(m_pActionList);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CActionList::Add
|
|
//
|
|
// Synopsis: Dynamic array function. Append the element at the end of the array
|
|
// Grow the array if nessesary
|
|
//
|
|
// Arguments: CAction* pAction - element to be added
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: Fengsun Created Header 11/14/97
|
|
// tomkel Fixed PREFIX issues 11/21/2000
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
void CActionList::Add(CAction* pAction)
|
|
{
|
|
MYDBGASSERT(m_nNum <= m_nSize);
|
|
MYDBGASSERT(m_nSize == 0 || m_pActionList!=NULL); // if (m_nSize!=0) ASSERT(m_pActionList!=NULL);
|
|
|
|
m_nNum++;
|
|
|
|
if (m_nNum > m_nSize)
|
|
{
|
|
//
|
|
// Either there is not enough room OR m_pActionList is NULL (this
|
|
// is the first call to Add). Need to allocate memory
|
|
//
|
|
|
|
CAction** pNewList = (CAction**)CmMalloc((m_nSize + GROW_BY)*sizeof(CAction*));
|
|
MYDBGASSERT(pNewList);
|
|
|
|
if (m_pActionList && pNewList)
|
|
{
|
|
//
|
|
// Memory was allocated and there is something to copy from m_pActionList
|
|
//
|
|
CopyMemory(pNewList, m_pActionList, (m_nSize)*sizeof(CAction*));
|
|
}
|
|
|
|
if (pNewList)
|
|
{
|
|
//
|
|
// Memory was allocated
|
|
//
|
|
CmFree(m_pActionList);
|
|
m_pActionList = pNewList;
|
|
m_nSize += GROW_BY;
|
|
|
|
//
|
|
// Add the action
|
|
//
|
|
m_pActionList[m_nNum - 1] = pAction;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Memory was not allocated, so Add did not happen
|
|
// Need to decrement the number of items in list (m_nNum)
|
|
// since it was inceremented at the beginning.
|
|
//
|
|
m_nNum--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Just add the action to the end
|
|
//
|
|
m_pActionList[m_nNum - 1] = pAction;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CActionList::GetAt
|
|
//
|
|
// Synopsis: Dynamic array fuction. Get the element at nIndex
|
|
//
|
|
// Arguments: UINT nIndex -
|
|
//
|
|
// Returns: inline CAction* -
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
inline CAction* CActionList::GetAt(UINT nIndex)
|
|
{
|
|
MYDBGASSERT(nIndex<m_nNum);
|
|
MYDBGASSERT(m_pActionList);
|
|
MYDBGASSERT(m_nNum <= m_nSize);
|
|
|
|
return m_pActionList[nIndex];
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CActionList::Append
|
|
//
|
|
// Synopsis: Append new actions to the list from profile
|
|
//
|
|
// Arguments: const CIni* piniService - The service file containing actions information
|
|
// LPCTSTR pszSection - The section name
|
|
//
|
|
// Returns: TRUE if an action was appended to the list
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
// nickball Removed current directory assumptions, and added piniProfile
|
|
// nickball Added Return code 03/22/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CActionList::Append(const CIni* piniService, LPCTSTR pszSection)
|
|
{
|
|
MYDBGASSERT(piniService);
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Read each of the entries and add to our list
|
|
// Start from 0 till the first empty entry
|
|
//
|
|
|
|
for (DWORD dwIdx=0; ; dwIdx++)
|
|
{
|
|
TCHAR szEntry[32]; // hold the entry name
|
|
|
|
wsprintfU(szEntry, TEXT("%u"), dwIdx);
|
|
LPTSTR pszCmd = piniService->GPPS(pszSection, szEntry); // Command line
|
|
|
|
if (*pszCmd == TEXT('\0'))
|
|
{
|
|
//
|
|
// No more entries
|
|
//
|
|
CmFree(pszCmd);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the flag
|
|
//
|
|
|
|
UINT iFlag = 0;
|
|
|
|
if (pszSection && pszSection[0])
|
|
{
|
|
wsprintfU(szEntry, c_pszCmEntryConactFlags, dwIdx); //0&Flags
|
|
iFlag = (UINT)piniService->GPPI(pszSection, szEntry, 0);
|
|
}
|
|
|
|
//
|
|
// Read the description
|
|
//
|
|
LPTSTR pszDescript = NULL;
|
|
|
|
wsprintfU(szEntry, c_pszCmEntryConactDesc, dwIdx); //0&Description
|
|
pszDescript = piniService->GPPS(pszSection, szEntry);
|
|
|
|
//
|
|
// CAction is responsible for releasing pszDescript
|
|
//
|
|
CAction* pAction = new CAction(pszCmd, iFlag, pszDescript);
|
|
CmFree(pszCmd);
|
|
|
|
if (pAction)
|
|
{
|
|
pAction->ConvertRelativePath(piniService);
|
|
ASSERT_VALID(pAction);
|
|
pAction->ExpandEnvironmentStringsInCommand();
|
|
Add(pAction);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
m_pszType = pszSection;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CActionList::RunAccordType
|
|
//
|
|
// Synopsis: Run the action list according to the connection type
|
|
//
|
|
// Arguments: HWND hwndDlg - The parent window
|
|
// _ArgsStruct *pArgs -
|
|
// BOOL fStatusMsgOnFailure - Whether to display a status message
|
|
// to the user in the event of failure
|
|
// BOOL fOnError - are we running OnError connect action?
|
|
//
|
|
// Returns: BOOL - FALSE, if some sync action failed to start or returns failed
|
|
//
|
|
// History: Fengsun Created Header 12/5/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CActionList::RunAccordType(HWND hwndDlg, _ArgsStruct *pArgs, BOOL fStatusMsgOnFailure, BOOL fOnError)
|
|
{
|
|
//
|
|
// Set the flag, so CM will not handle WM_TIMER and RAS messages
|
|
//
|
|
pArgs->fIgnoreTimerRasMsg = TRUE;
|
|
BOOL fRetValue = Run(hwndDlg, pArgs, FALSE, fStatusMsgOnFailure, fOnError);//fAddWatch = FALSE
|
|
pArgs->fIgnoreTimerRasMsg = FALSE;
|
|
|
|
return fRetValue;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CActionList::Run
|
|
//
|
|
// Synopsis: Run the action list
|
|
//
|
|
// Arguments: HWND hwndDlg - The parent window, which is diabled during the process
|
|
// ArgsStruct *pArgs -
|
|
// BOOL fAddWatch - If true, will add the process as watch process,
|
|
// BOOL fStatusMsgOnFailure - Whether to display a status message
|
|
// to the user in the event of failure
|
|
// BOOL fOnError - are we running OnError connect action?
|
|
//
|
|
// Returns: BOOL - FALSE, if some sync action failed to start or returns failed
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CActionList::Run(HWND hwndDlg, ArgsStruct *pArgs, BOOL fAddWatch, BOOL fStatusMsgOnFailure, BOOL fOnError)
|
|
{
|
|
//
|
|
// Disable the window, and enable it on return
|
|
//
|
|
|
|
CFreezeWindow FreezeWindow(hwndDlg);
|
|
|
|
for (UINT i = 0; i < GetSize(); i++)
|
|
{
|
|
CAction* pAction = (CAction*)GetAt(i);
|
|
|
|
DWORD dwLoadType = (DWORD)-1;
|
|
ASSERT_VALID(pAction);
|
|
MYDBGASSERT(m_pszType);
|
|
|
|
//
|
|
// Lets check the flags value to see if this connect action should
|
|
// run for this type of connection.
|
|
//
|
|
if (FALSE == pAction->RunConnectActionForCurrentConnection(pArgs))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Replace %xxxx% with the value
|
|
//
|
|
pAction->ExpandMacros(pArgs);
|
|
|
|
//
|
|
// Also expand any environment variables
|
|
// NOTE: the order (macros vs. env vars) is deliberate. Macros get
|
|
// expanded first.
|
|
//
|
|
pAction->ExpandEnvironmentStringsInParams();
|
|
|
|
//
|
|
// Check to see if we can run the action @ this moment
|
|
//
|
|
|
|
if (FALSE == pAction->IsAllowed(pArgs, &dwLoadType))
|
|
{
|
|
//
|
|
// If not allowed, log the fact that we didn't run this connect action
|
|
// and then just skip it.
|
|
//
|
|
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If this customaction might bring up UI
|
|
//
|
|
if (pAction->HasUI())
|
|
{
|
|
//
|
|
// If we are in unattended mode, don't run any connect actions
|
|
//
|
|
if (pArgs->dwFlags & FL_UNATTENDED)
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
CMTRACE(TEXT("Run: skipped past a customaction because we are in unattended mode"));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Custom actions processed during a Fast User Switch can put up UI requiring
|
|
// user input, effectively blocking CM.
|
|
//
|
|
if (pArgs->fInFastUserSwitch)
|
|
{
|
|
CMASSERTMSG((CM_CREDS_GLOBAL != pArgs->dwCurrentCredentialType),
|
|
TEXT("CActionList::Run - in FUS disconnect, but connectoid has global creds!"));
|
|
|
|
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
CMTRACE(TEXT("Run: skipped past a singleuser DLL connectaction because of FUS"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (pAction->IsDll())
|
|
{
|
|
DWORD dwActionRetValue=0; // the connect action return value, in COM format
|
|
BOOL bLoadSucceed = FALSE;
|
|
|
|
if (hwndDlg)
|
|
{
|
|
//
|
|
// Display description for DLL
|
|
//
|
|
if (pAction->GetDescription())
|
|
{
|
|
LPTSTR lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_RUNNING, pAction->GetDescription());
|
|
//
|
|
// Update the main dialog status window
|
|
//
|
|
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
|
|
CmFree(lpszText);
|
|
}
|
|
}
|
|
|
|
bLoadSucceed = pAction->RunAsDll(hwndDlg, dwActionRetValue, dwLoadType);
|
|
|
|
if (bLoadSucceed)
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTIONDLL, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()),
|
|
pAction->GetProgram(), dwActionRetValue);
|
|
}
|
|
else
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()),
|
|
pAction->GetProgram());
|
|
}
|
|
|
|
//
|
|
// Failed to start the action, or the action returned failure
|
|
//
|
|
|
|
if (FAILED(dwActionRetValue) || !bLoadSucceed)
|
|
{
|
|
LPTSTR lpszText = NULL;
|
|
|
|
if (fStatusMsgOnFailure &&
|
|
hwndDlg &&
|
|
pAction->GetDescription())
|
|
{
|
|
if (bLoadSucceed)
|
|
{
|
|
lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_FAILED,
|
|
pAction->GetDescription(), dwActionRetValue);
|
|
}
|
|
else
|
|
{
|
|
lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_NOTFOUND,
|
|
pAction->GetDescription());
|
|
}
|
|
//
|
|
// Update the main dialog status window
|
|
//
|
|
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
|
|
}
|
|
|
|
if (!fOnError)
|
|
{
|
|
DWORD dwError = 0;
|
|
|
|
if (bLoadSucceed)
|
|
{
|
|
dwError = dwActionRetValue;
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_DLL_NOT_FOUND;
|
|
}
|
|
|
|
pArgs->Log.Log(ONERROR_EVENT, dwError, pAction->GetDescription());
|
|
|
|
//
|
|
// We'll run On-Error connect actions if we are not already running OnError
|
|
// connect action. This is to prevent infinite loops.
|
|
//
|
|
CActionList OnErrorActList;
|
|
OnErrorActList.Append(pArgs->piniService, c_pszCmSectionOnError);
|
|
|
|
//
|
|
// fStatusMsgOnFailure = FALSE
|
|
//
|
|
OnErrorActList.RunAccordType(hwndDlg, pArgs, FALSE, TRUE);
|
|
|
|
//
|
|
// Update the program state
|
|
//
|
|
if (fStatusMsgOnFailure)
|
|
{
|
|
lstrcpynU(pArgs->szLastErrorSrc, pAction->GetDescription(), MAX_LASTERR_LEN);
|
|
pArgs->dwExitCode = dwError;
|
|
SetInteractive(pArgs->hwndMainDlg, pArgs);
|
|
pArgs->psState = PS_Error;
|
|
}
|
|
}
|
|
|
|
if (lpszText)
|
|
{
|
|
//
|
|
// restore the failure msg of the previous connect action
|
|
//
|
|
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
|
|
CmFree(lpszText);
|
|
}
|
|
|
|
//
|
|
// Note that if a DLL connect action fails, we will stop processing connect actions.
|
|
// If the fStatusMsgOnFailure flag is set, then we won't show an error message
|
|
// but connect action processing will still halt (we do this in cases where the user
|
|
// isn't going to care such as oncancel actions, onerror actions, and cases where
|
|
// disconnect action fail).
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HANDLE hProcess = NULL;
|
|
TCHAR szDesktopName[MAX_PATH];
|
|
TCHAR szWinDesktop[MAX_PATH];
|
|
|
|
if (IsLogonAsSystem())
|
|
{
|
|
DWORD cb;
|
|
HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
|
|
|
|
//
|
|
// Get the name of the desktop. Normally returns default or Winlogon or system or WinNT
|
|
// On Win95/98 GetUserObjectInformation is not supported and thus the desktop name
|
|
// will be empty so we will use the good old API
|
|
//
|
|
szDesktopName[0] = 0;
|
|
|
|
if (hDesk && GetUserObjectInformation(hDesk, UOI_NAME, szDesktopName, sizeof(szDesktopName), &cb))
|
|
{
|
|
lstrcpyU(szWinDesktop, TEXT("Winsta0\\"));
|
|
lstrcatU(szWinDesktop, szDesktopName);
|
|
|
|
CMTRACE1(TEXT("CActionList::Run - Desktop = %s"), MYDBGSTR(szWinDesktop));
|
|
|
|
hProcess = pAction->RunAsExeFromSystem(&pArgs->m_ShellDll, szWinDesktop, dwLoadType);
|
|
|
|
if (NULL != hProcess)
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTIONEXE, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
}
|
|
else
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Don't run action if we don't have desktop
|
|
//
|
|
|
|
CMTRACE1(TEXT("CActionList::Run/GetUserObjectInformation failed, GLE=%u"), GetLastError());
|
|
continue;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
hProcess = pAction->RunAsExe(&pArgs->m_ShellDll);
|
|
|
|
if (NULL != hProcess)
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTIONEXE, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
}
|
|
else
|
|
{
|
|
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
|
|
}
|
|
}
|
|
|
|
if (hProcess)
|
|
{
|
|
if (fAddWatch)
|
|
{
|
|
AddWatchProcess(pArgs,hProcess); // watch for process termination
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hProcess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::ParseCmdLine
|
|
//
|
|
// Synopsis: This function parses the given command line into the program,
|
|
// dll function name (if required), and the parameters (if any).
|
|
// The individual command line parts are stored in member vars.
|
|
//
|
|
// Arguments: LPTSTR pszCmdLine - connect action command line to parse
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: quintinb original code in Profwiz.cpp ReadConList()
|
|
// fengsun copied and modified 4/16/98
|
|
// quintinb Rewrote and commonized with the Profwiz version 04/21/00
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
void CAction::ParseCmdLine(LPTSTR pszCmdLine)
|
|
{
|
|
m_pszFunction = m_pszProgram = m_pszParams = NULL;
|
|
|
|
CmStrTrim(pszCmdLine);
|
|
|
|
HRESULT hr = HrParseCustomActionString(pszCmdLine, &m_pszProgram, &m_pszParams, &m_pszFunction);
|
|
|
|
MYDBGASSERT(SUCCEEDED(hr));
|
|
|
|
if (NULL == m_pszProgram)
|
|
{
|
|
MYDBGASSERT(FALSE); // we should never have a NULL program
|
|
m_pszProgram = CmStrCpyAlloc(TEXT(""));
|
|
}
|
|
|
|
if (NULL == m_pszParams)
|
|
{
|
|
m_pszParams = CmStrCpyAlloc(TEXT(""));
|
|
}
|
|
|
|
if (NULL == m_pszFunction)
|
|
{
|
|
m_pszFunction = CmStrCpyAlloc(TEXT(""));
|
|
}
|
|
|
|
//
|
|
// If we have a function, then the program was a Dll
|
|
//
|
|
m_fIsDll = (m_pszFunction && (TEXT('\0') != m_pszFunction[0]));
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::CAction
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: LPTSTR lpCommandLine - The command read from the profile
|
|
// CAction is responsible to free it
|
|
// UINT dwFlags - The flags read from the profile
|
|
// LPTSTR lpDescript - The description of the connect action read from
|
|
// profile. CAction is responsible to free it.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: fengsun Created Header 4/15/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CAction::CAction(LPTSTR lpCommandLine, UINT dwFlags, LPTSTR lpDescript)
|
|
{
|
|
m_dwFlags = dwFlags;
|
|
m_pszDescription = lpDescript;
|
|
|
|
//
|
|
// Get all information from command line, including
|
|
// Program name, function name, parameters
|
|
//
|
|
ParseCmdLine(lpCommandLine);
|
|
|
|
//
|
|
// If this is a DLL, but there is no description, use the name of the file
|
|
// Can not use C Run Time routine _tsplitpath()
|
|
//
|
|
|
|
if (m_fIsDll && (m_pszDescription == NULL || m_pszDescription[0]==TEXT('\0')))
|
|
{
|
|
//
|
|
// Find the last '\\' to get only the file name
|
|
//
|
|
LPTSTR pszTmp = CmStrrchr(m_pszProgram, '\\');
|
|
if (pszTmp == NULL)
|
|
{
|
|
pszTmp = m_pszProgram;
|
|
}
|
|
else
|
|
{
|
|
pszTmp++;
|
|
}
|
|
|
|
CmFree(m_pszDescription);
|
|
m_pszDescription = CmStrCpyAlloc(pszTmp);
|
|
}
|
|
}
|
|
|
|
CAction::~CAction()
|
|
{
|
|
CmFree(m_pszProgram);
|
|
CmFree(m_pszParams);
|
|
CmFree(m_pszFunction);
|
|
CmFree(m_pszDescription);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::RunAsDll
|
|
//
|
|
// Synopsis: Run the action as a Dll
|
|
// Format is: DllName.dll FunctionName Argument
|
|
// Long file name is enclosed by '+'
|
|
//
|
|
// Arguments: HWND hwndDlg - The parent window
|
|
// DWORD& dwReturnValue - The return value of the dll fuction
|
|
// DWORD dwLoadType - The permitted load location
|
|
//
|
|
// Returns: BOOL - TRUE, if the action is a Dll
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CAction::RunAsDll(HWND hwndDlg, OUT DWORD& dwReturnValue, DWORD dwLoadType) const
|
|
{
|
|
MYDBGASSERT(IsDll());
|
|
|
|
dwReturnValue = FALSE;
|
|
|
|
LPWSTR pszwModuleName = NULL;
|
|
|
|
//
|
|
// Determine the module name to be used
|
|
//
|
|
|
|
if (!GetLoadDirWithAlloc(dwLoadType, &pszwModuleName))
|
|
{
|
|
CMASSERTMSG(FALSE, TEXT("CAction::RunAsDll -- GetLoadDirWithAlloc Failed."));
|
|
CmFree(pszwModuleName);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Load the module
|
|
//
|
|
|
|
HINSTANCE hLibrary = LoadLibraryExU(pszwModuleName, NULL, 0);
|
|
|
|
if (NULL == hLibrary)
|
|
{
|
|
CMTRACE2(TEXT("RunAsDll() LoadLibrary(%s) failed, GLE=%u."),
|
|
MYDBGSTR(pszwModuleName), GetLastError());
|
|
|
|
CmFree(pszwModuleName);
|
|
return FALSE;
|
|
}
|
|
|
|
pfnCmConnectActionFunc pfnFunc;
|
|
LPSTR pszFunctionName = NULL;
|
|
LPSTR pszParams = NULL;
|
|
|
|
#ifdef UNICODE
|
|
pszFunctionName = WzToSzWithAlloc(m_pszFunction);
|
|
#else
|
|
pszFunctionName = m_pszFunction;
|
|
#endif
|
|
|
|
//
|
|
// Get the Procedure Address
|
|
//
|
|
pfnFunc = (pfnCmConnectActionFunc)GetProcAddress(hLibrary, pszFunctionName);
|
|
|
|
#ifdef UNICODE
|
|
CmFree(pszFunctionName);
|
|
#endif
|
|
|
|
|
|
if (pfnFunc)
|
|
{
|
|
#if !defined (DEBUG)
|
|
__try
|
|
{
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
pszParams = WzToSzWithAlloc(m_pszParams);
|
|
#else
|
|
pszParams = m_pszParams;
|
|
#endif
|
|
|
|
//
|
|
// Execute the Function
|
|
//
|
|
dwReturnValue = pfnFunc(hwndDlg, hLibrary, pszParams, SW_SHOW);
|
|
|
|
#ifdef UNICODE
|
|
CmFree(pszParams);
|
|
#endif
|
|
|
|
CMTRACE1(TEXT("RunAsDll() Executed module: %s"), MYDBGSTR(pszwModuleName));
|
|
CMTRACE1(TEXT("\tFunction: %s"), MYDBGSTR(m_pszFunction));
|
|
CMTRACE1(TEXT("\tParams: %s"), MYDBGSTR(m_pszParams));
|
|
CMTRACE2(TEXT("\t Return Value: %u = 0x%x"), dwReturnValue, dwReturnValue);
|
|
|
|
#if !defined (DEBUG)
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
dwReturnValue = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
CMTRACE3(TEXT("RunAsDll() GetProcAddress(*pszwModuleName=%s,*m_pszFunction=%s) failed, GLE=%u."),
|
|
MYDBGSTR(pszwModuleName), MYDBGSTR(m_pszFunction), GetLastError());
|
|
}
|
|
|
|
CmFree(pszwModuleName);
|
|
FreeLibrary(hLibrary);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::RunAsExe
|
|
//
|
|
// Synopsis: Run the action as an exe or other shell object
|
|
//
|
|
// Arguments: CShellDll* pShellDll, pointer to the link to shell32.dll
|
|
//
|
|
// Returns: HANDLE - The action Process handle, for Win32 only
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HANDLE CAction::RunAsExe(CShellDll* pShellDll) const
|
|
{
|
|
// Now we have the exe name and args separated, execute it
|
|
|
|
SHELLEXECUTEINFO seiInfo;
|
|
|
|
ZeroMemory(&seiInfo,sizeof(seiInfo));
|
|
seiInfo.cbSize = sizeof(seiInfo);
|
|
seiInfo.fMask |= SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
|
|
seiInfo.lpFile = m_pszProgram;
|
|
seiInfo.lpParameters = m_pszParams;
|
|
seiInfo.nShow = SW_SHOW;
|
|
|
|
MYDBGASSERT(pShellDll);
|
|
|
|
if (!pShellDll->ExecuteEx(&seiInfo))
|
|
{
|
|
CMTRACE3(TEXT("RunAsExe() ShellExecuteEx() of %s %s GLE=%u."),
|
|
MYDBGSTR(m_pszProgram), MYDBGSTR(m_pszParams), GetLastError());
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return seiInfo.hProcess;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::GetLoadDirWithAlloc
|
|
//
|
|
// Synopsis: Uses the dwLoadType parameter to decide how the path should be
|
|
// modified. This is used in the WinLogon context to prevent just
|
|
// any executable from being executed. Must be from the profile dir
|
|
// or the system dir.
|
|
//
|
|
// Arguments: DWORD dwLoadType - Load type, currently 0 == system dir, 1 == profile dir (default)
|
|
// LPWSTR pszwPath - string buffer to put the modified path in
|
|
//
|
|
// Returns: BOOL - TRUE if successful
|
|
//
|
|
// History: quintinb Created 01/11/2000
|
|
// sumitc Change to alloc retval 05/08/2000
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CAction::GetLoadDirWithAlloc(IN DWORD dwLoadType, OUT LPWSTR * ppszwPath) const
|
|
{
|
|
LPWSTR psz = NULL;
|
|
UINT cch = 0;
|
|
|
|
//
|
|
// Check that we have an output buffer
|
|
//
|
|
if (NULL == ppszwPath)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Compute how much space we need
|
|
//
|
|
if (dwLoadType)
|
|
{
|
|
// 1 = profile dir
|
|
cch += lstrlen(m_pszProgram) + 1;
|
|
}
|
|
else
|
|
{
|
|
// 0 = system dir
|
|
cch = GetSystemDirectoryU(NULL, 0);
|
|
cch += lstrlen(TEXT("\\"));
|
|
cch += lstrlen(m_pszProgram) + 1; // is the +1 already in the GetSystemDir retval?
|
|
}
|
|
|
|
//
|
|
// Allocate it
|
|
//
|
|
psz = (LPWSTR) CmMalloc(sizeof(TCHAR) * cch);
|
|
if (NULL == psz)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Process the load type
|
|
//
|
|
if (dwLoadType)
|
|
{
|
|
//
|
|
// If relative path, this will already be expanded.
|
|
//
|
|
|
|
lstrcpyU(psz, m_pszProgram);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Force the system directory
|
|
//
|
|
if (0 == GetSystemDirectoryU(psz, cch))
|
|
{
|
|
CmFree(psz);
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcatU(psz, TEXT("\\"));
|
|
lstrcatU(psz, m_pszProgram);
|
|
}
|
|
|
|
*ppszwPath = psz;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::RunAsExeFromSystem
|
|
//
|
|
// Synopsis: Run the action as an exe or other shell object on the choosen desktop
|
|
//
|
|
// Arguments: CShellDll* pShellDll - pointer to the link to shell32.dll
|
|
// LPTSTR pszDesktop - name of the desktop to execute the exe on
|
|
// DWORD dwLoadType - location from which to load the exe
|
|
//
|
|
// Returns: HANDLE - The action Process handle, for Win32 only
|
|
//
|
|
// History: v-vijayb Created 07/19/99
|
|
// nickball Removed fSecurity 07/27/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HANDLE CAction::RunAsExeFromSystem(CShellDll* pShellDll, LPTSTR pszDesktop, DWORD dwLoadType)
|
|
{
|
|
STARTUPINFO StartupInfo = {0};
|
|
PROCESS_INFORMATION ProcessInfo = {0};
|
|
LPWSTR pszwFullPath = NULL;
|
|
LPWSTR pszwCommandLine = NULL;
|
|
|
|
MYDBGASSERT(OS_NT);
|
|
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
if (pszDesktop)
|
|
{
|
|
StartupInfo.lpDesktop = pszDesktop;
|
|
StartupInfo.wShowWindow = SW_SHOW;
|
|
}
|
|
|
|
//
|
|
// Use an explicit path to the modules to be launched, this
|
|
// prevents CreateProcess from picking something up on the path.
|
|
//
|
|
if (!GetLoadDirWithAlloc(dwLoadType, &pszwFullPath))
|
|
{
|
|
CMASSERTMSG(FALSE, TEXT("CAction::RunAsExeFromSystem -- GetLoadDirWithAlloc Failed."));
|
|
goto Cleanup;
|
|
}
|
|
|
|
pszwCommandLine = CmStrCpyAlloc(m_pszProgram);
|
|
if (NULL == pszwCommandLine)
|
|
{
|
|
CMASSERTMSG(FALSE, TEXT("CAction::RunAsExeFromSystem -- CmStrCpyAlloc Failed."));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Add parameters
|
|
//
|
|
|
|
if (NULL == CmStrCatAlloc(&pszwCommandLine, TEXT(" ")))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (NULL == CmStrCatAlloc(&pszwCommandLine, m_pszParams))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
CMTRACE1(TEXT("RunAsExeFromSystem/CreateProcess() - Launching %s"), pszwCommandLine);
|
|
|
|
//
|
|
// Launch the modules, this could be CreateProcessU but it isn't necessary as this only runs on NT
|
|
//
|
|
|
|
if (NULL == CreateProcess(pszwFullPath, pszwCommandLine,
|
|
NULL, NULL, FALSE, 0,
|
|
NULL, NULL,
|
|
&StartupInfo, &ProcessInfo))
|
|
{
|
|
CMTRACE2(TEXT("RunAsExeFromSystem() CreateProcess() of %s failed, GLE=%u."), pszwCommandLine, GetLastError());
|
|
|
|
ProcessInfo.hProcess = NULL;
|
|
ProcessInfo.hThread = NULL;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (ProcessInfo.hThread)
|
|
{
|
|
CloseHandle(ProcessInfo.hThread);
|
|
}
|
|
|
|
CmFree(pszwFullPath);
|
|
CmFree(pszwCommandLine);
|
|
|
|
return ProcessInfo.hProcess;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::ExpandMacros
|
|
//
|
|
// Synopsis: Replace the %xxxxx% in command line with the corresponding value
|
|
//
|
|
// Arguments: ArgsStruct *pArgs -
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: fengsun Created Header 11/14/97
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
void CAction::ExpandMacros(ArgsStruct *pArgs)
|
|
{
|
|
MYDBGASSERT(pArgs);
|
|
|
|
LPTSTR pszCurr = m_pszParams;
|
|
BOOL bValidPropertyName;
|
|
|
|
while (*pszCurr)
|
|
{
|
|
if (*pszCurr == TEXT('%'))
|
|
{
|
|
LPTSTR pszNextPercent = CmStrchr(pszCurr + 1, TEXT('%'));
|
|
if (pszNextPercent)
|
|
{
|
|
LPTSTR pszTmp = (LPTSTR) CmMalloc((DWORD)((pszNextPercent-pszCurr))*sizeof(TCHAR));
|
|
if (pszTmp)
|
|
{
|
|
CopyMemory(pszTmp,pszCurr+1,(pszNextPercent-pszCurr-1)*sizeof(TCHAR));
|
|
|
|
//
|
|
// Get the value from name
|
|
//
|
|
LPTSTR pszMid = pArgs->GetProperty(pszTmp, &bValidPropertyName);
|
|
|
|
//
|
|
// If the property does not exist, use "NULL"
|
|
//
|
|
if (pszMid == NULL)
|
|
{
|
|
pszMid = CmStrCpyAlloc(TEXT("NULL"));
|
|
}
|
|
else if (pszMid[0] == TEXT('\0'))
|
|
{
|
|
CmFree(pszMid);
|
|
pszMid = CmStrCpyAlloc(TEXT("NULL"));
|
|
}
|
|
else if ( (lstrcmpiU(pszTmp,TEXT("Profile")) == 0) ||
|
|
CmStrchr(pszMid, TEXT(' ')) != NULL)
|
|
{
|
|
//
|
|
// If the name is %Profile% or the value has a space in it,
|
|
// Put the string in double quote
|
|
//
|
|
LPTSTR pszValueInQuote = (LPTSTR)CmMalloc((lstrlenU(pszMid)+3)*sizeof(pszMid[0]));
|
|
if (pszValueInQuote)
|
|
{
|
|
lstrcpyU(pszValueInQuote, TEXT("\""));
|
|
lstrcatU(pszValueInQuote, pszMid);
|
|
lstrcatU(pszValueInQuote, TEXT("\""));
|
|
|
|
CmFree(pszMid);
|
|
pszMid = pszValueInQuote;
|
|
}
|
|
else
|
|
{
|
|
CMTRACE1(TEXT("ExpandMacros() malloc failed, can't put string in double quotes, GLE=%u."), GetLastError());
|
|
}
|
|
}
|
|
|
|
//
|
|
// if bValidPropertyName is FALSE then leave untouched.
|
|
//
|
|
|
|
if (FALSE == bValidPropertyName)
|
|
{
|
|
pszCurr = pszNextPercent + 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Replace %xxxx% with the value
|
|
//
|
|
DWORD dwLenPre = (DWORD)(pszCurr - m_pszParams);
|
|
DWORD dwLenMid = lstrlenU(pszMid);
|
|
DWORD dwLenPost = lstrlenU(pszNextPercent+1);
|
|
CmFree(pszTmp);
|
|
pszTmp = m_pszParams;
|
|
m_pszParams = (LPTSTR) CmMalloc((dwLenPre + dwLenMid + dwLenPost + 1)*sizeof(TCHAR));
|
|
if (m_pszParams)
|
|
{
|
|
CopyMemory(m_pszParams, pszTmp, dwLenPre*sizeof(TCHAR)); // before %
|
|
lstrcatU(m_pszParams, pszMid); //append value
|
|
lstrcatU(m_pszParams, pszNextPercent+1); // after %
|
|
pszCurr = m_pszParams + dwLenPre + dwLenMid;
|
|
}
|
|
else
|
|
{
|
|
// we're out of memory
|
|
CMTRACE1(TEXT("ExpandMacros() malloc failed, can't strip off %% signs, GLE=%u."), GetLastError());
|
|
m_pszParams = pszTmp;
|
|
}
|
|
}
|
|
CmFree(pszMid);
|
|
}
|
|
CmFree(pszTmp);
|
|
}
|
|
else
|
|
{
|
|
pszCurr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszCurr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::AssertValid
|
|
//
|
|
// Synopsis: For debug purpose only, assert the connection object is valid
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: Created Header 2/12/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
void CAction::AssertValid() const
|
|
{
|
|
MYDBGASSERT(m_pszProgram && m_pszProgram[0]);
|
|
MYDBGASSERT(m_fIsDll == TRUE || m_fIsDll == FALSE);
|
|
}
|
|
#endif
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::ExpandEnvironmentStrings
|
|
//
|
|
// Synopsis: Utility fn to expand environment variables in the given string
|
|
//
|
|
// Arguments: ppsz - ptr to string (usually member variable)
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: SumitC Created 29-Feb-2000
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
void CAction::ExpandEnvironmentStrings(LPTSTR * ppsz)
|
|
{
|
|
DWORD cLen;
|
|
|
|
MYDBGASSERT(*ppsz);
|
|
|
|
//
|
|
// find out how much memory we need to allocate
|
|
//
|
|
cLen = ExpandEnvironmentStringsU(*ppsz, NULL, 0);
|
|
|
|
if (cLen)
|
|
{
|
|
LPTSTR pszTemp = (LPTSTR) CmMalloc((cLen + 1) * sizeof(TCHAR));
|
|
|
|
if (pszTemp)
|
|
{
|
|
DWORD cLen2 = ExpandEnvironmentStringsU(*ppsz, pszTemp, cLen);
|
|
MYDBGASSERT(cLen == cLen2);
|
|
|
|
if (cLen2)
|
|
{
|
|
CmFree(*ppsz);
|
|
*ppsz = pszTemp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::IsAllowed
|
|
//
|
|
// Synopsis: checks Registry to see if a command is allowed to run
|
|
//
|
|
// Arguments: _ArgsStruct *pArgs - Ptr to global args struct
|
|
// LPDWORD lpdwLoadType - Ptr to DWORD to be filled with load type
|
|
//
|
|
// Returns: TRUE if action is allowed @ this time
|
|
//
|
|
// Notes: Checks SOFTWARE\Microsoft\Connection Manager\<ServiceName>
|
|
// Under which you will have the Values for each command
|
|
// 0 - system32 directory
|
|
// 1 - profile directory
|
|
// History: v-vijayb Created Header 7/20/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CAction::IsAllowed(_ArgsStruct *pArgs, LPDWORD lpdwLoadType)
|
|
{
|
|
return IsActionEnabled(m_pszProgram, pArgs->szServiceName, pArgs->piniService->GetFile(), lpdwLoadType);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CAction::RunConnectActionForCurrentConnection
|
|
//
|
|
// Synopsis: This function compares the flags value of the connect action
|
|
// with the current connection type (from pArgs->GetTypeOfConnection).
|
|
// It returns TRUE if the connect action should be run for this type
|
|
// and FALSE if the connect action should be skipped.
|
|
//
|
|
// Arguments: _ArgsStruct *pArgs - Ptr to global args struct
|
|
//
|
|
// Returns: TRUE if action should be executed
|
|
//
|
|
// History: quintinb Created 04/20/00
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CAction::RunConnectActionForCurrentConnection(_ArgsStruct *pArgs)
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
DWORD dwType = pArgs->GetTypeOfConnection();
|
|
|
|
if (DIAL_UP_CONNECTION == dwType)
|
|
{
|
|
//
|
|
// Don't run direct only or tunnel connect actions
|
|
// on a dialup connection.
|
|
//
|
|
if ((m_dwFlags & DIRECT_ONLY) || (m_dwFlags & ALL_TUNNEL))
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else if (DIRECT_CONNECTION == dwType)
|
|
{
|
|
//
|
|
// Don't run dialup only or dialup connect actions
|
|
// on a direct connection.
|
|
//
|
|
if ((m_dwFlags & DIALUP_ONLY) || (m_dwFlags & ALL_DIALUP))
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else if (DOUBLE_DIAL_CONNECTION == dwType)
|
|
{
|
|
//
|
|
// Don't run dialup only or dialup connect actions
|
|
// on a direct connection.
|
|
//
|
|
if ((m_dwFlags & DIALUP_ONLY) || (m_dwFlags & DIRECT_ONLY))
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CMASSERTMSG(FALSE, TEXT("CActionList::Run -- unknown connection type, skipping action"));
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|