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.
789 lines
21 KiB
789 lines
21 KiB
|
|
//
|
|
// CTBGlobal.cpp
|
|
//
|
|
// Contains the methods and properties for the global object used in TBScript.
|
|
// In scripting, you do not need to references these prefixed by "Global.",
|
|
// you can simply use them like any other global method or propery.
|
|
//
|
|
// Copyright (C) 2001 Microsoft Corporation
|
|
//
|
|
// Author: a-devjen (Devin Jenson)
|
|
//
|
|
|
|
|
|
#include "CTBGlobal.h"
|
|
#include <time.h>
|
|
#include <crtdbg.h>
|
|
#include <shellapi.h>
|
|
|
|
|
|
#define CTBOBJECT CTBGlobal
|
|
#include "virtualdefs.h"
|
|
|
|
|
|
// This is a workaround for a Microsoft header file bug
|
|
#ifndef INVALID_SET_FILE_POINTER
|
|
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
|
#endif // INVALID_SET_FILE_POINTER
|
|
|
|
|
|
// This is the function format for each property
|
|
#define PROPCODE(Name, Value) \
|
|
STDMETHODIMP CTBGlobal::get_##Name(DWORD *Result) \
|
|
{ \
|
|
*Result = Value; \
|
|
return NOERROR; \
|
|
}
|
|
|
|
|
|
PROPCODE(TSFLAG_COMPRESSION, 0x01);
|
|
PROPCODE(TSFLAG_BITMAPCACHE, 0x02);
|
|
PROPCODE(TSFLAG_FULLSCREEN, 0x04);
|
|
|
|
PROPCODE(VK_CANCEL, 0x03); // Control-break processing
|
|
PROPCODE(VK_BACK, 0x08); // BACKSPACE key
|
|
PROPCODE(VK_TAB, 0x09); // TAB key
|
|
PROPCODE(VK_CLEAR, 0x0C); // CLEAR key
|
|
PROPCODE(VK_RETURN, 0x0D); // ENTER key
|
|
PROPCODE(VK_ENTER, 0x0D); // ENTER key (backward compatibility ONLY)
|
|
PROPCODE(VK_SHIFT, 0x10); // SHIFT key
|
|
PROPCODE(VK_CONTROL, 0x11); // CTRL key
|
|
PROPCODE(VK_MENU, 0x12); // ALT key
|
|
PROPCODE(VK_PAUSE, 0x13); // PAUSE key
|
|
PROPCODE(VK_ESCAPE, 0x1B); // ESC key
|
|
PROPCODE(VK_SPACE, 0x20); // SPACEBAR
|
|
PROPCODE(VK_PRIOR, 0x21); // PAGE UP key
|
|
PROPCODE(VK_NEXT, 0x22); // PAGE DOWN key
|
|
PROPCODE(VK_END, 0x23); // END key
|
|
PROPCODE(VK_HOME, 0x24); // HOME key
|
|
PROPCODE(VK_LEFT, 0x25); // LEFT ARROW key
|
|
PROPCODE(VK_UP, 0x26); // UP ARROW key
|
|
PROPCODE(VK_RIGHT, 0x27); // RIGHT ARROW key
|
|
PROPCODE(VK_DOWN, 0x28); // DOWN ARROW key
|
|
PROPCODE(VK_SNAPSHOT, 0x2C); // PRINT SCREEN key
|
|
PROPCODE(VK_INSERT, 0x2D); // INS key
|
|
PROPCODE(VK_DELETE, 0x2E); // DEL key
|
|
PROPCODE(VK_0, 0x30); // 0 key
|
|
PROPCODE(VK_1, 0x31); // 1 key
|
|
PROPCODE(VK_2, 0x32); // 2 key
|
|
PROPCODE(VK_3, 0x33); // 3 key
|
|
PROPCODE(VK_4, 0x34); // 4 key
|
|
PROPCODE(VK_5, 0x35); // 5 key
|
|
PROPCODE(VK_6, 0x36); // 6 key
|
|
PROPCODE(VK_7, 0x37); // 7 key
|
|
PROPCODE(VK_8, 0x38); // 8 key
|
|
PROPCODE(VK_9, 0x39); // 9 key
|
|
PROPCODE(VK_A, 0x41); // A key
|
|
PROPCODE(VK_B, 0x42); // B key
|
|
PROPCODE(VK_C, 0x43); // C key
|
|
PROPCODE(VK_D, 0x44); // D key
|
|
PROPCODE(VK_E, 0x45); // E key
|
|
PROPCODE(VK_F, 0x46); // F key
|
|
PROPCODE(VK_G, 0x47); // G key
|
|
PROPCODE(VK_H, 0x48); // H key
|
|
PROPCODE(VK_I, 0x49); // I key
|
|
PROPCODE(VK_J, 0x4A); // J key
|
|
PROPCODE(VK_K, 0x4B); // K key
|
|
PROPCODE(VK_L, 0x4C); // L key
|
|
PROPCODE(VK_M, 0x4D); // M key
|
|
PROPCODE(VK_N, 0x4E); // N key
|
|
PROPCODE(VK_O, 0x4F); // O key
|
|
PROPCODE(VK_P, 0x50); // P key
|
|
PROPCODE(VK_Q, 0x51); // Q key
|
|
PROPCODE(VK_R, 0x52); // R key
|
|
PROPCODE(VK_S, 0x53); // S key
|
|
PROPCODE(VK_T, 0x54); // T key
|
|
PROPCODE(VK_U, 0x55); // U key
|
|
PROPCODE(VK_V, 0x56); // V key
|
|
PROPCODE(VK_W, 0x57); // W key
|
|
PROPCODE(VK_X, 0x58); // X key
|
|
PROPCODE(VK_Y, 0x59); // Y key
|
|
PROPCODE(VK_Z, 0x5A); // Z key
|
|
PROPCODE(VK_LWIN, 0x5B); // Left Windows key
|
|
PROPCODE(VK_RWIN, 0x5C); // Right Windows key
|
|
PROPCODE(VK_APPS, 0x5D); // Applications key
|
|
PROPCODE(VK_NUMPAD0, 0x60); // Numeric keypad 0 key
|
|
PROPCODE(VK_NUMPAD1, 0x61); // Numeric keypad 1 key
|
|
PROPCODE(VK_NUMPAD2, 0x62); // Numeric keypad 2 key
|
|
PROPCODE(VK_NUMPAD3, 0x63); // Numeric keypad 3 key
|
|
PROPCODE(VK_NUMPAD4, 0x64); // Numeric keypad 4 key
|
|
PROPCODE(VK_NUMPAD5, 0x65); // Numeric keypad 5 key
|
|
PROPCODE(VK_NUMPAD6, 0x66); // Numeric keypad 6 key
|
|
PROPCODE(VK_NUMPAD7, 0x67); // Numeric keypad 7 key
|
|
PROPCODE(VK_NUMPAD8, 0x68); // Numeric keypad 8 key
|
|
PROPCODE(VK_NUMPAD9, 0x69); // Numeric keypad 9 key
|
|
PROPCODE(VK_MULTIPLY, 0x6A); // Multiply key
|
|
PROPCODE(VK_ADD, 0x6B); // Add key
|
|
PROPCODE(VK_SEPARATOR, 0x6C); // Separator key
|
|
PROPCODE(VK_SUBTRACT, 0x6D); // Subtract key
|
|
PROPCODE(VK_DECIMAL, 0x6E); // Decimal key
|
|
PROPCODE(VK_DIVIDE, 0x6F); // Divide key
|
|
PROPCODE(VK_F1, 0x70); // F1 key
|
|
PROPCODE(VK_F2, 0x71); // F2 key
|
|
PROPCODE(VK_F3, 0x72); // F3 key
|
|
PROPCODE(VK_F4, 0x73); // F4 key
|
|
PROPCODE(VK_F5, 0x74); // F5 key
|
|
PROPCODE(VK_F6, 0x75); // F6 key
|
|
PROPCODE(VK_F7, 0x76); // F7 key
|
|
PROPCODE(VK_F8, 0x77); // F8 key
|
|
PROPCODE(VK_F9, 0x78); // F9 key
|
|
PROPCODE(VK_F10, 0x79); // F10 key
|
|
PROPCODE(VK_F11, 0x7A); // F11 key
|
|
PROPCODE(VK_F12, 0x7B); // F12 key
|
|
PROPCODE(VK_F13, 0x7C); // F13 key
|
|
PROPCODE(VK_F14, 0x7D); // F14 key
|
|
PROPCODE(VK_F15, 0x7E); // F15 key
|
|
PROPCODE(VK_F16, 0x7F); // F16 key
|
|
PROPCODE(VK_F17, 0x80); // F17 key
|
|
PROPCODE(VK_F18, 0x81); // F18 key
|
|
PROPCODE(VK_F19, 0x82); // F19 key
|
|
PROPCODE(VK_F20, 0x83); // F20 key
|
|
PROPCODE(VK_F21, 0x84); // F21 key
|
|
PROPCODE(VK_F22, 0x85); // F22 key
|
|
PROPCODE(VK_F23, 0x86); // F23 key
|
|
PROPCODE(VK_F24, 0x87); // F24 key
|
|
|
|
|
|
// CTBGlobal::CTBGlobal
|
|
//
|
|
// The constructor. Loads the TypeInfo for interface.
|
|
//
|
|
// No return value.
|
|
|
|
CTBGlobal::CTBGlobal(void)
|
|
{
|
|
// Initialize base object stuff
|
|
Init(IID_ITBGlobal);
|
|
|
|
ScriptEngine = NULL;
|
|
fnPrintMessage = NULL;
|
|
TBShell = NULL;
|
|
|
|
// Get the performance frequency (used if the
|
|
// script called GetInterval()
|
|
if (QueryPerformanceFrequency(&SysPerfFrequency) == FALSE)
|
|
SysPerfFrequency.QuadPart = 0;
|
|
}
|
|
|
|
|
|
// CTBGlobal::~CTBGlobal
|
|
//
|
|
// The destructor.
|
|
//
|
|
// No return value.
|
|
|
|
CTBGlobal::~CTBGlobal(void)
|
|
{
|
|
// Release the shell if we have a handle
|
|
if (TBShell != NULL)
|
|
TBShell->Release();
|
|
|
|
TBShell = NULL;
|
|
|
|
UnInit();
|
|
}
|
|
|
|
|
|
// Sets the script engine handle needed for LoadScript()
|
|
void CTBGlobal::SetScriptEngine(HANDLE ScriptEngineHandle)
|
|
{
|
|
ScriptEngine = ScriptEngineHandle;
|
|
}
|
|
|
|
|
|
// Sets a pointer to the callback routine needed for DebugMessage()
|
|
void CTBGlobal::SetPrintMessage(PFNPRINTMESSAGE PrintMessage)
|
|
{
|
|
fnPrintMessage = PrintMessage;
|
|
}
|
|
|
|
|
|
// This is to make it possible to globally access the shell
|
|
void CTBGlobal::SetShellObjPtr(CTBShell *TBShellPtr)
|
|
{
|
|
// Make sure we arn't setting a shell we already have
|
|
if (TBShellPtr == TBShell)
|
|
return;
|
|
|
|
// If we already have a handle, release the current one
|
|
if (TBShell != NULL)
|
|
TBShell->Release();
|
|
|
|
// Set the new one
|
|
TBShell = TBShellPtr;
|
|
|
|
// Add a reference to the new one
|
|
if (TBShell != NULL)
|
|
TBShell->AddRef();
|
|
}
|
|
|
|
|
|
// CTBGlobal::WinExecuteEx
|
|
//
|
|
// Executes the specified command into a new process, and
|
|
// optionally return immediately or wait. This function is
|
|
// used as a helper function only.
|
|
//
|
|
// If WaitForProcess is FALSE, Result will contain TRUE or FALSE.
|
|
// If WaitForProcess is TRUE, Result will contain the ExitCode.
|
|
//
|
|
// Returns S_OK on success, or E_FAIL on failure.
|
|
|
|
HRESULT CTBGlobal::WinExecuteEx(BSTR Command, BOOL WaitForProcess, DWORD *Result)
|
|
{
|
|
PROCESS_INFORMATION ProcessInfo = { 0 };
|
|
STARTUPINFOW StartupInfo = { 0 };
|
|
OLECHAR CommandEval[MAX_PATH] = { 0 };
|
|
|
|
// Evaluate environment variables first of all
|
|
if (ExpandEnvironmentStringsW(Command, CommandEval,
|
|
SIZEOF_ARRAY(CommandEval)) == 0) {
|
|
|
|
if (WaitForProcess == TRUE)
|
|
*Result = -1;
|
|
else
|
|
*Result = FALSE;
|
|
|
|
// Cause an exception
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Initialize the structure size
|
|
StartupInfo.cb = sizeof(STARTUPINFO);
|
|
|
|
// Begin the process
|
|
if (CreateProcessW(NULL, CommandEval, NULL, NULL, FALSE,
|
|
NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo,
|
|
&ProcessInfo) == FALSE) {
|
|
|
|
// Process didn't execute, could be just an invalid name
|
|
if (WaitForProcess == TRUE)
|
|
*Result = -1;
|
|
else
|
|
*Result = FALSE;
|
|
|
|
// Don't cause an exception
|
|
return S_OK;
|
|
}
|
|
|
|
// Wait for the process to complete (if specified)
|
|
if (WaitForProcess == TRUE)
|
|
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
|
|
|
|
// Get the result/exit code
|
|
if (WaitForProcess == TRUE)
|
|
*Result = GetExitCodeProcess(ProcessInfo.hProcess, Result);
|
|
else
|
|
*Result = TRUE;
|
|
|
|
// Close process handles
|
|
CloseHandle(ProcessInfo.hThread);
|
|
CloseHandle(ProcessInfo.hProcess);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Begin Methods used within script
|
|
//
|
|
//
|
|
|
|
|
|
// CTBGlobal::DebugAlert
|
|
//
|
|
// Opens a Win32 MessageBox containing the specified text.
|
|
// Used for debugging purposes.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::DebugAlert(BSTR Text)
|
|
{
|
|
if (Text != NULL)
|
|
MessageBoxW(0, Text, L"Alert", MB_SETFOREGROUND);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::DebugAlert
|
|
//
|
|
// Opens a Win32 MessageBox containing the specified text.
|
|
// Used for debugging purposes.
|
|
//
|
|
// Returns S_OK on success or E_OUTOFMEMORY on failure.
|
|
|
|
STDMETHODIMP CTBGlobal::DebugMessage(BSTR Text)
|
|
{
|
|
if (fnPrintMessage != NULL && Text != NULL && *Text != OLECHAR('\0')) {
|
|
|
|
// Create a new buffer for us to use
|
|
int BufLen = wcslen(Text) + 1;
|
|
|
|
char *TextA = (char *)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY, BufLen);
|
|
|
|
// Validate
|
|
if (TextA == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Copy WC over to our character string
|
|
wcstombs(TextA, Text, BufLen);
|
|
|
|
// Broadcast our new find
|
|
if (fnPrintMessage != NULL)
|
|
fnPrintMessage(SCRIPT_MESSAGE, "%s", TextA);
|
|
|
|
// Free the memory
|
|
HeapFree(GetProcessHeap(), 0, TextA);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetArguments
|
|
//
|
|
// Retrieves the user defined argument string passed into the
|
|
// scripting interface when first created.
|
|
//
|
|
// Returns S_OK on success or E_OUTOFMEMORY on failure.
|
|
|
|
STDMETHODIMP CTBGlobal::GetArguments(BSTR *Args)
|
|
{
|
|
// Create and allocate the string over OLE.
|
|
*Args = SysAllocString(TBShell->GetArguments());
|
|
|
|
// Check allocation
|
|
if (*Args == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetDesiredUserName
|
|
//
|
|
// Retrieves the username which was originally desired to
|
|
// be used when the script was first started.
|
|
//
|
|
// Returns S_OK on success or E_OUTOFMEMORY on failure.
|
|
|
|
STDMETHODIMP CTBGlobal::GetDesiredUserName(BSTR *UserName)
|
|
{
|
|
// Create and allocate the string over OLE.
|
|
*UserName = SysAllocString(TBShell->GetDesiredUserName());
|
|
|
|
// Check allocation
|
|
if (*UserName == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::LoadScript
|
|
//
|
|
// Loads a new script, and begins execution in the specified
|
|
// file. The method returns when execution in the file
|
|
// has terminated.
|
|
//
|
|
// Returns S_OK on success or E_FAIL on failure.
|
|
|
|
STDMETHODIMP CTBGlobal::LoadScript(BSTR FileName, BOOL *Result)
|
|
{
|
|
// Do a quick check on the file name
|
|
if (FileName != NULL && *FileName != OLECHAR('\0')) {
|
|
|
|
// Run the file
|
|
if (SCPParseScriptFile(ScriptEngine, FileName) == FALSE) {
|
|
|
|
*Result = FALSE;
|
|
return E_FAIL;
|
|
}
|
|
|
|
// We succeeded
|
|
*Result = TRUE;
|
|
}
|
|
else
|
|
|
|
// We failed to parse the script, but invalid file name
|
|
// is not merit to bring up a script exception.
|
|
*Result = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::Sleep
|
|
//
|
|
// Uses the Win32 API Sleep() to sleep for the specified time.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::Sleep(DWORD Milliseconds)
|
|
{
|
|
if(Milliseconds > 0)
|
|
::Sleep(Milliseconds);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetDefaultWPM
|
|
//
|
|
// Returns the recorded default Words Per Minute.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::GetDefaultWPM(DWORD *WordsPerMinute)
|
|
{
|
|
_ASSERT(TBShell != NULL);
|
|
|
|
*WordsPerMinute = TBShell->GetDefaultWPM();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::SetDefaultWPM
|
|
//
|
|
// Changes the default Words Per Minute for typing.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::SetDefaultWPM(DWORD WordsPerMinute)
|
|
{
|
|
_ASSERT(TBShell != NULL);
|
|
|
|
TBShell->SetDefaultWPM(WordsPerMinute);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetLatency
|
|
//
|
|
// Retreives the current latency for multi-action commands.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::GetLatency(DWORD *Latency)
|
|
{
|
|
_ASSERT(TBShell != NULL);
|
|
|
|
*Latency = TBShell->GetLatency();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::SetLatency
|
|
//
|
|
// Changes the current latency for multi-action commands.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::SetLatency(DWORD Latency)
|
|
{
|
|
_ASSERT(TBShell != NULL);
|
|
|
|
TBShell->SetLatency(Latency);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetInterval
|
|
//
|
|
// Results the number of milliseconds since the local machine
|
|
// has been started. The result is zero if the machine does not
|
|
// support performance queries. WARNING: the value has a huge
|
|
// potential to wrap back to zero if the machine has been up for
|
|
// a substantial amount of time.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::GetInterval(DWORD *Time)
|
|
{
|
|
LARGE_INTEGER Counter;
|
|
|
|
// Grab the data
|
|
if (QueryPerformanceCounter(&Counter) == FALSE ||
|
|
SysPerfFrequency.QuadPart == 0)
|
|
|
|
// One of the functions failed if we reached here,
|
|
// Set the result as 0
|
|
*Time = 0;
|
|
|
|
else
|
|
|
|
// Otherwise, set the milliseconds
|
|
*Time = (DWORD)((Counter.QuadPart * 1000) /
|
|
SysPerfFrequency.QuadPart);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::DeleteFile
|
|
//
|
|
// Deletes a file on the local file system.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::DeleteFile(BSTR FileName, BOOL *Result)
|
|
{
|
|
*Result = DeleteFileW(FileName);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::MoveFile
|
|
//
|
|
// Moves a file on the local file system. If the destination
|
|
// filename already exists, it is overwritten.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::MoveFile(BSTR OldFileName,
|
|
BSTR NewFileName, BOOL *Result)
|
|
{
|
|
*Result = MoveFileExW(OldFileName, NewFileName,
|
|
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::CopyFile
|
|
//
|
|
// Copies a file on the local file system. If the destination
|
|
// filename already exists, it is overwritten.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::CopyFile(BSTR OldFileName,
|
|
BSTR NewFileName, BOOL *Result)
|
|
{
|
|
*Result = CopyFileW(OldFileName, NewFileName, FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::CreateDirectory
|
|
//
|
|
// Creates a directory on the local file system.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::CreateDirectory(BSTR DirName, BOOL *Result)
|
|
{
|
|
*Result = CreateDirectoryW(DirName, NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::RemoveDirectory
|
|
//
|
|
// Recursively removes a directory and all members under it. This
|
|
// works like the old DELTREE DOS command.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::RemoveDirectory(BSTR DirName, BOOL *Result)
|
|
{
|
|
// Use the shell method so we don't have to write a
|
|
// long annoying recursive function
|
|
SHFILEOPSTRUCTW FileOp = { 0 };
|
|
FileOp.wFunc = FO_DELETE;
|
|
FileOp.pFrom = DirName;
|
|
FileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
|
|
|
|
// Call the shell API - now wasn't that easy?
|
|
*Result = (SHFileOperationW(&FileOp) == 0);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::FileExists
|
|
//
|
|
// Checks whether the file exists or not, this will also work on
|
|
// directories. The result is TRUE if the file exists, otherwise
|
|
// FALSE.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::FileExists(BSTR FileName, BOOL *Result)
|
|
{
|
|
// Simply open the file
|
|
HANDLE File = CreateFileW(FileName, 0,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
// If File is invalid, it didn't exist
|
|
*Result = (File != INVALID_HANDLE_VALUE);
|
|
|
|
// Close the file
|
|
if (File != INVALID_HANDLE_VALUE)
|
|
CloseHandle(File);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::SetCurrentDirectory
|
|
//
|
|
// Sets the current working directory.
|
|
//
|
|
// Returns S_OK.
|
|
|
|
STDMETHODIMP CTBGlobal::SetCurrentDirectory(BSTR Directory, BOOL *Result)
|
|
{
|
|
*Result = SetCurrentDirectoryW(Directory);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::GetCurrentDirectory
|
|
//
|
|
// Gets the current working directory.
|
|
//
|
|
// Returns S_OK or E_OUTOFMEMORY.
|
|
|
|
STDMETHODIMP CTBGlobal::GetCurrentDirectory(BSTR *Directory)
|
|
{
|
|
OLECHAR *Buffer = NULL;
|
|
DWORD BufLenResult;
|
|
|
|
// First get the number of bytes needed for our buffer
|
|
DWORD BufferLen = GetCurrentDirectoryW(0, NULL);
|
|
|
|
_ASSERT(BufferLen != 0);
|
|
|
|
// Allocate our local buffer
|
|
Buffer = (OLECHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(OLECHAR) * BufferLen);
|
|
if ( Buffer == NULL ) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
// Copy the current directory to our buffer
|
|
BufLenResult = GetCurrentDirectoryW(BufferLen, Buffer);
|
|
|
|
// Check if we failed some freakish way
|
|
_ASSERT(BufLenResult < BufferLen);
|
|
|
|
// Now copy the string over to an OLE buffer
|
|
*Directory = SysAllocString(Buffer);
|
|
|
|
// Free our old buffer
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
|
|
// Return proper result
|
|
return (*Directory != NULL) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
// CTBGlobal::WriteToFile
|
|
//
|
|
// Appends the specified text to teh specified file. If the file
|
|
// does not exist, it is created.
|
|
//
|
|
// Returns S_OK or E_OUTOFMEMORY.
|
|
|
|
STDMETHODIMP CTBGlobal::WriteToFile(BSTR FileName, BSTR Text, BOOL *Result)
|
|
{
|
|
DWORD SetFilePtrResult;
|
|
DWORD BytesWritten;
|
|
char *TextA;
|
|
int BufLen;
|
|
HANDLE File;
|
|
|
|
// Don't do anything for writing empty strings
|
|
if (Text == NULL || *Text == OLECHAR('\0')) {
|
|
|
|
// We didn't write anything, but this is not merit for an exception
|
|
*Result = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
// Get the destination buffer length
|
|
BufLen = wcslen(Text) + 1;
|
|
|
|
// Allocate the buffer
|
|
TextA = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufLen);
|
|
|
|
if (TextA == NULL) {
|
|
|
|
*Result = FALSE;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Copy the OLE string over to our ASCII buffer
|
|
wcstombs(TextA, Text, BufLen);
|
|
|
|
// Open/Create the file
|
|
File = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
// Check the result of opening the file
|
|
if (File == INVALID_HANDLE_VALUE) {
|
|
|
|
HeapFree(GetProcessHeap(), 0, TextA);
|
|
|
|
*Result = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
// Move the pointer to the end of the file
|
|
SetFilePtrResult = SetFilePointer(File, 0, NULL, FILE_END);
|
|
|
|
_ASSERT(SetFilePtrResult != INVALID_SET_FILE_POINTER);
|
|
|
|
// Write the text
|
|
*Result = WriteFile(File, TextA, BufLen - 1, &BytesWritten, NULL);
|
|
|
|
// Close the file and return
|
|
CloseHandle(File);
|
|
|
|
// Free the temp ASCII buffer
|
|
HeapFree(GetProcessHeap(), 0, TextA);
|
|
|
|
return (*Result == FALSE) ? E_FAIL : S_OK;
|
|
}
|
|
|
|
|
|
// CTBGlobal::WinCommand
|
|
//
|
|
// Executes the specified command into a new process.
|
|
// The function only returns when the new process has terminated.
|
|
//
|
|
// Returns S_OK on success, or E_FAIL on failure.
|
|
|
|
STDMETHODIMP CTBGlobal::WinCommand(BSTR Command, DWORD *Result)
|
|
{
|
|
// Call the helper API
|
|
return WinExecuteEx(Command, TRUE, Result);
|
|
}
|
|
|
|
|
|
// CTBGlobal::WinExecute
|
|
//
|
|
// Executes the specified command into a new process, and returns.
|
|
// The function does not wait for the new process to terminate.
|
|
//
|
|
// Returns S_OK or E_OUTOFMEMORY.
|
|
|
|
STDMETHODIMP CTBGlobal::WinExecute(BSTR Command, BOOL *Result)
|
|
{
|
|
// Call the helper API
|
|
return WinExecuteEx(Command, FALSE, (DWORD *)Result);
|
|
}
|