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.
644 lines
16 KiB
644 lines
16 KiB
|
|
//
|
|
// CTBShell.cpp
|
|
//
|
|
// Contains the methods and properties for the shell object used in TBScript.
|
|
// In scripting, to access any members you must prefix the member with "TS.".
|
|
//
|
|
// Copyright (C) 2001 Microsoft Corporation
|
|
//
|
|
// Author: a-devjen (Devin Jenson)
|
|
//
|
|
|
|
|
|
#include <crtdbg.h>
|
|
#include "CTBShell.h"
|
|
|
|
|
|
#define CTBOBJECT CTBShell
|
|
#include "virtualdefs.h"
|
|
|
|
|
|
// CTBShell::CTBShell
|
|
//
|
|
// The constructor.. just initializes data.
|
|
//
|
|
// No return value.
|
|
|
|
CTBShell::CTBShell(void)
|
|
{
|
|
// Initialize base object stuff
|
|
Init(IID_ITBShell);
|
|
|
|
Connection = NULL;
|
|
|
|
// Clean up local structures
|
|
ZeroMemory(&CurrentUser, sizeof(CurrentUser));
|
|
ZeroMemory(&LastErrorString, sizeof(LastErrorString));
|
|
ZeroMemory(&DesiredData, sizeof(DesiredData));
|
|
|
|
// Set default resolution
|
|
DesiredData.xRes = SCP_DEFAULT_RES_X;
|
|
DesiredData.yRes = SCP_DEFAULT_RES_Y;
|
|
|
|
// Set default words per minute
|
|
SetDefaultWPM(T2_DEFAULT_WORDS_PER_MIN);
|
|
SetLatency(T2_DEFAULT_LATENCY);
|
|
}
|
|
|
|
|
|
// CTBShell::~CTBShell
|
|
//
|
|
// The destructor.. just unitializes data.
|
|
//
|
|
// No return value.
|
|
|
|
CTBShell::~CTBShell(void)
|
|
{
|
|
UnInit();
|
|
}
|
|
|
|
|
|
// CTBShell::RecordLastError
|
|
//
|
|
// This method simply records the last error string, and
|
|
// if specified, records the TRUE/FALSE success state according
|
|
// to the specified string.
|
|
//
|
|
// Returns S_OK to prevent script exceptions.
|
|
|
|
HRESULT CTBShell::RecordLastError(LPCSTR Error, BOOL *Result)
|
|
{
|
|
// Just terminate our error string if no error is passed in
|
|
if (Error == NULL)
|
|
*LastErrorString = OLECHAR('\0');
|
|
|
|
// Otherwise, convert the string from ASCII to multibyte
|
|
else
|
|
mbstowcs(LastErrorString, Error,
|
|
sizeof(LastErrorString) / sizeof(*LastErrorString));
|
|
|
|
// If we want the result, enter that in as well
|
|
if (Result != NULL)
|
|
*Result = (Error == NULL) ? TRUE : FALSE;
|
|
|
|
// Return the proper HRESULT
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBShell::RecordOrThrow
|
|
//
|
|
// This first calls RecordLastError to complete the
|
|
// recording operation. Then if Error is non-NULL,
|
|
// a return value is returned to indicate to OLE that
|
|
// an exception should be thrown
|
|
//
|
|
// Returns S_OK if the string is NULL, and E_FAIL if not.
|
|
|
|
HRESULT CTBShell::RecordOrThrow(LPCSTR Error, BOOL *Result, HRESULT ErrReturn)
|
|
{
|
|
// Do the normal record operation
|
|
RecordLastError(Error, Result);
|
|
|
|
// If we have failure indication, return E_FAIL which causes OLE
|
|
// to cause an error in the script.
|
|
return (Error == NULL) ? S_OK : ErrReturn;
|
|
}
|
|
|
|
|
|
// CTBShell::SetParam
|
|
//
|
|
// Sets a user defined LPARAM value needed for callback purposes.
|
|
//
|
|
// No return value.
|
|
|
|
void CTBShell::SetParam(LPARAM lParam)
|
|
{
|
|
this->lParam = lParam;
|
|
}
|
|
|
|
|
|
// CTBShell::SetDesiredData
|
|
//
|
|
// Allows for the class to reference to access
|
|
// user-desired data passed to the app.
|
|
//
|
|
// No return value.
|
|
|
|
void CTBShell::SetDesiredData(TSClientData *DesiredDataPtr)
|
|
{
|
|
// Simply copy over the structure
|
|
if (DesiredDataPtr != NULL)
|
|
DesiredData = *DesiredDataPtr;
|
|
|
|
// Validate the resolution.. note we don't have to go too
|
|
// far here because TCLIENT does some better checks.
|
|
if (DesiredData.xRes == 0)
|
|
DesiredData.xRes = SCP_DEFAULT_RES_X;
|
|
|
|
if (DesiredData.yRes == 0)
|
|
DesiredData.yRes = SCP_DEFAULT_RES_Y;
|
|
|
|
// We have this data, now modify the Words Per Minute value.
|
|
SetDefaultWPM(DesiredData.WordsPerMinute);
|
|
}
|
|
|
|
|
|
// CTBShell::SetDefaultWPM
|
|
//
|
|
// Sets the default WPM for the shell.
|
|
//
|
|
// No return value.
|
|
|
|
void CTBShell::SetDefaultWPM(DWORD WordsPerMinute)
|
|
{
|
|
// If WordsPerMinute is 0 (which in essence, would not be typing
|
|
// at all), change it to the default.
|
|
if (WordsPerMinute == 0)
|
|
WordsPerMinute = T2_DEFAULT_WORDS_PER_MIN;
|
|
|
|
// Change global desired data structure to reflect the new value.
|
|
DesiredData.WordsPerMinute = WordsPerMinute;
|
|
|
|
// And change the value over on TCLIENT2 as well
|
|
if (Connection != NULL)
|
|
T2SetDefaultWPM(Connection, WordsPerMinute);
|
|
}
|
|
|
|
|
|
// CTBShell::GetDefaultWPM
|
|
//
|
|
// Retrieves the default WPM for the shell.
|
|
//
|
|
// Returns the default words per minute.
|
|
|
|
DWORD CTBShell::GetDefaultWPM(void)
|
|
{
|
|
return DesiredData.WordsPerMinute;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetLatency
|
|
//
|
|
// Retreives the current latency for multi-action commands.
|
|
//
|
|
// Returns the current latency.
|
|
|
|
DWORD CTBShell::GetLatency(void)
|
|
{
|
|
return CurrentLatency;
|
|
}
|
|
|
|
|
|
// CTBShell::SetLatency
|
|
//
|
|
// Changes the current latency for multi-action commands.
|
|
//
|
|
// No return value.
|
|
|
|
void CTBShell::SetLatency(DWORD Latency)
|
|
{
|
|
// Change it locally
|
|
CurrentLatency = Latency;
|
|
|
|
// And also via the TCLIENT2 API
|
|
if (Connection != NULL)
|
|
T2SetLatency(Connection, Latency);
|
|
}
|
|
|
|
|
|
// CTBShell::GetArguments
|
|
//
|
|
// Retrieves arguments which the shell was originally started with.
|
|
// Do not modify this value!! It is only used for copying. The
|
|
// only way to modify this value is during creation of the ScriptEngine
|
|
// within the DesiredData structure - you pass in an argument string.
|
|
//
|
|
// Returns a pointer to the arguments string.
|
|
|
|
LPCWSTR CTBShell::GetArguments(void)
|
|
{
|
|
return DesiredData.Arguments;
|
|
}
|
|
|
|
|
|
// CTBShell::GetDesiredUserName
|
|
//
|
|
// Retrieves the name in which the app initially wanted to login with.
|
|
// Do not modify this value!! It is only used for copying. The
|
|
// only way to modify this value is during creation of the ScriptEngine
|
|
// within the DesiredData structure - you set the user name there.
|
|
//
|
|
// Returns a pointer to a string containing a user name.
|
|
|
|
LPCWSTR CTBShell::GetDesiredUserName(void)
|
|
{
|
|
return DesiredData.User;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Begin methods which are directly exported through COM into script.
|
|
//
|
|
//
|
|
|
|
|
|
// CTBShell::Connect
|
|
//
|
|
// Simply way to connect to the desired server.
|
|
|
|
STDMETHODIMP CTBShell::Connect(BOOL *Result)
|
|
{
|
|
return ConnectEx(
|
|
DesiredData.Server,
|
|
DesiredData.User,
|
|
DesiredData.Pass,
|
|
DesiredData.Domain,
|
|
DesiredData.xRes,
|
|
DesiredData.yRes,
|
|
DesiredData.Flags,
|
|
DesiredData.BPP,
|
|
DesiredData.AudioFlags,
|
|
Result);
|
|
}
|
|
|
|
|
|
// CTBShell::Connect
|
|
//
|
|
// Extended way to connect to a server.
|
|
|
|
STDMETHODIMP CTBShell::ConnectEx(BSTR ServerName, BSTR UserName,
|
|
BSTR Password, BSTR Domain, INT xRes, INT yRes,
|
|
INT Flags, INT BPP, INT AudioFlags, BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Make sure we don't have a connection yet
|
|
if (Connection != NULL)
|
|
return RecordLastError("Already connected", Result);
|
|
|
|
// Use the T2ConnectEx function in TCLIENT2 API to connect
|
|
LastError = T2ConnectEx(ServerName, UserName, Password, Domain,
|
|
L"explorer", xRes, yRes, Flags, BPP, AudioFlags, &Connection);
|
|
|
|
// Verify connection...
|
|
if (LastError == NULL) {
|
|
|
|
// Successful, save the current user
|
|
wcscpy(CurrentUser, UserName);
|
|
|
|
// And default data for the connection
|
|
T2SetParam(Connection, lParam);
|
|
T2SetDefaultWPM(Connection, DesiredData.WordsPerMinute);
|
|
T2SetLatency(Connection, CurrentLatency);
|
|
}
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::Disconnect
|
|
//
|
|
// Disconnect from an active server.
|
|
|
|
STDMETHODIMP CTBShell::Disconnect(BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Disconnect
|
|
if ((LastError = T2Disconnect(Connection)) == NULL)
|
|
Connection = NULL;
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::GetBuildNumber
|
|
//
|
|
// Retrieves the build number if retrieved while
|
|
// connecting. If no build number has been retreived,
|
|
// 0 (zero) is the result.
|
|
|
|
STDMETHODIMP CTBShell::GetBuildNumber(DWORD *BuildNum)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection
|
|
if (Connection == NULL) {
|
|
|
|
*BuildNum = 0;
|
|
return RecordLastError("Not connected");
|
|
}
|
|
|
|
// Get the build number and return
|
|
LastError = T2GetBuildNumber(Connection, BuildNum);
|
|
|
|
return RecordLastError(LastError, NULL);
|
|
}
|
|
|
|
|
|
// CTBShell::GetCurrentUserName
|
|
//
|
|
// If connected, retreives the logged on name.
|
|
|
|
STDMETHODIMP CTBShell::GetCurrentUserName(BSTR *UserName)
|
|
{
|
|
// Sanity check the connection
|
|
if (Connection == NULL) {
|
|
|
|
*UserName = SysAllocString(L"");
|
|
return RecordLastError("Not connected");
|
|
}
|
|
|
|
// Copy the username
|
|
*UserName = SysAllocString(CurrentUser);
|
|
|
|
// Check the result
|
|
if (*UserName == NULL)
|
|
return RecordOrThrow("Not enough memory", NULL, E_OUTOFMEMORY);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBShell::GetLastError
|
|
//
|
|
// Retreives a description of the last error that occured.
|
|
|
|
STDMETHODIMP CTBShell::GetLastError(BSTR *LastError)
|
|
{
|
|
// Copy the string over OLE
|
|
*LastError = SysAllocString(LastErrorString);
|
|
|
|
// Check the result
|
|
if (*LastError == NULL)
|
|
return RecordOrThrow("Not enough memory", NULL, E_OUTOFMEMORY);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBShell::IsConnected
|
|
//
|
|
// Retreives a boolean indicating whether the handle is fully
|
|
// connected or not.
|
|
|
|
STDMETHODIMP CTBShell::IsConnected(BOOL *Result)
|
|
{
|
|
*Result = (Connection == NULL) ? FALSE : TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBShell::Logoff
|
|
//
|
|
// Attempts to have the active connection logoff.
|
|
|
|
STDMETHODIMP CTBShell::Logoff(BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Use the TCLIENT2 API to logoff
|
|
if ((LastError = T2Logoff(Connection)) == NULL)
|
|
Connection = NULL;
|
|
|
|
// Return success state
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::WaitForText
|
|
//
|
|
// Puts the current thread into a wait state until the specified
|
|
// text is passed from the active connection. Optionally, you can set
|
|
// a timeout value which will make the function fail over the specified
|
|
// number of milliseconds.
|
|
|
|
STDMETHODIMP CTBShell::WaitForText(BSTR Text, INT Timeout, BOOL *Result)
|
|
{
|
|
// Sanity check the connection
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Call the API
|
|
LPCSTR LastError = T2WaitForText(Connection, Text, Timeout);
|
|
|
|
// Retirm success state
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::WaitForTextAndSleep
|
|
//
|
|
// This is exactly the same as a combonation of two calls:
|
|
//
|
|
// TS.WaitForText();
|
|
// TS.Sleep();
|
|
//
|
|
// but put into one function. This is because this combonation is
|
|
// used so frequently, using this method drastically shrinks the size
|
|
// of a script.
|
|
|
|
STDMETHODIMP CTBShell::WaitForTextAndSleep(BSTR Text, INT Time, BOOL *Result)
|
|
{
|
|
// Call TS.WaitForText()
|
|
HRESULT OLEResult = WaitForText(Text, -1, Result);
|
|
|
|
// Call Sleep()
|
|
if (OLEResult == S_OK)
|
|
Sleep(Time);
|
|
|
|
return OLEResult;
|
|
}
|
|
|
|
|
|
// CTBShell::SendMessage
|
|
//
|
|
// Sends a Windows Message the active terminal connection.
|
|
|
|
STDMETHODIMP CTBShell::SendMessage(UINT Message,
|
|
WPARAM wParam, LPARAM lParam, BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Call the TCLIENT2 API
|
|
LastError = T2SendData(Connection, Message, wParam, lParam);
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::TypeText
|
|
//
|
|
// Types text at a specified rate.
|
|
|
|
STDMETHODIMP CTBShell::TypeText(BSTR Text, UINT WordsPerMin, BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Call the TCLIENT2 API
|
|
LastError = T2TypeText(Connection, Text, WordsPerMin);
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::OpenStartMenu
|
|
//
|
|
// Does a CTRL-ESC on the remote client to bring up the start menu.
|
|
|
|
STDMETHODIMP CTBShell::OpenStartMenu(BOOL *Result)
|
|
{
|
|
// CTRL+ESC for the Start Menu
|
|
VKeyCtrl(VK_ESCAPE, Result);
|
|
|
|
if (Result == FALSE)
|
|
return RecordLastError("Failed to CTRL-ESC", NULL);
|
|
|
|
// Wait for "Shut Down" on the start menu to appear
|
|
return WaitForText(OLESTR("Shut Down"), T2INFINITE, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::OpenSystemMenu
|
|
//
|
|
// Does an ALT-SPACE on the remote client to bring up the system menu.
|
|
|
|
STDMETHODIMP CTBShell::OpenSystemMenu(BOOL *Result)
|
|
{
|
|
// ALT+SPACE to open the system menu
|
|
VKeyAlt(VK_SPACE, Result);
|
|
|
|
if (Result == FALSE)
|
|
return RecordLastError("Failed to ALT-SPACE", NULL);
|
|
|
|
// Wait for "Close" on the system menu to appear
|
|
return WaitForText(OLESTR("Close"), T2INFINITE, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::Maximize
|
|
//
|
|
// Attempts to use the system menu to maximize the active window.
|
|
|
|
STDMETHODIMP CTBShell::Maximize(BOOL *Result)
|
|
{
|
|
// Open the system menu
|
|
HRESULT OLEResult = OpenSystemMenu(Result);
|
|
|
|
// Hit 'x' for maximize
|
|
if (Result != FALSE)
|
|
OLEResult = KeyPress(OLESTR("x"), Result);
|
|
|
|
return OLEResult;
|
|
}
|
|
|
|
|
|
// CTBShell::Minimize
|
|
//
|
|
// Attempts to use the system menu to minimize the active window.
|
|
|
|
STDMETHODIMP CTBShell::Minimize(BOOL *Result)
|
|
{
|
|
// Open the system menu
|
|
HRESULT OLEResult = OpenSystemMenu(Result);
|
|
|
|
// Hit 'x' for maximize
|
|
if (Result != FALSE)
|
|
OLEResult = KeyPress(OLESTR("n"), Result);
|
|
|
|
return OLEResult;
|
|
}
|
|
|
|
|
|
// CTBShell::Start
|
|
//
|
|
// Uses the TCLIENT2 function to open the start menu,
|
|
// hit r (for run), and type the specified name to run
|
|
// a program.
|
|
|
|
STDMETHODIMP CTBShell::Start(BSTR Name, BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection.
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Call the API
|
|
LastError = T2Start(Connection, Name);
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
// CTBShell::SwitchToProcess
|
|
//
|
|
// Uses the TCLIENT2 function to ALT-TAB between programs until the
|
|
// specified text is found, which then the current application is opened.
|
|
|
|
STDMETHODIMP CTBShell::SwitchToProcess(BSTR Name, BOOL *Result)
|
|
{
|
|
LPCSTR LastError;
|
|
|
|
// Sanity check the connection.
|
|
if (Connection == NULL)
|
|
return RecordLastError("Not connected", Result);
|
|
|
|
// Call the API
|
|
LastError = T2SwitchToProcess(Connection, Name);
|
|
|
|
return RecordLastError(LastError, Result);
|
|
}
|
|
|
|
|
|
|
|
// This macros allows to quickly define the key methods.
|
|
// Because they are so similar, this macro is nice as it
|
|
// only makes you to change code once if need be.
|
|
|
|
#define CTBSHELL_ENABLEPTR *
|
|
#define CTBSHELL_DISABLEPTR
|
|
|
|
#define CTBSHELL_KEYFUNCTYPE(Name, Type, Ptr) \
|
|
STDMETHODIMP CTBShell::Name(Type Key, BOOL *Result) \
|
|
{ \
|
|
LPCSTR LastError = T2##Name(Connection, Ptr Key); \
|
|
if (Connection == NULL) \
|
|
return RecordLastError("Not connected", Result); \
|
|
return RecordLastError(LastError, Result); \
|
|
}
|
|
|
|
// This quick macro allows for declaring both the ASCII
|
|
// version and the virtual key code one both in one swipe.
|
|
|
|
#define CTBSHELL_KEYFUNCS(Name) \
|
|
CTBSHELL_KEYFUNCTYPE(Name, BSTR, CTBSHELL_ENABLEPTR); \
|
|
CTBSHELL_KEYFUNCTYPE(V##Name, INT, CTBSHELL_DISABLEPTR);
|
|
|
|
// Key function defintions
|
|
|
|
CTBSHELL_KEYFUNCS(KeyAlt);
|
|
CTBSHELL_KEYFUNCS(KeyCtrl);
|
|
CTBSHELL_KEYFUNCS(KeyDown);
|
|
CTBSHELL_KEYFUNCS(KeyPress);
|
|
CTBSHELL_KEYFUNCS(KeyUp);
|