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.
742 lines
20 KiB
742 lines
20 KiB
|
|
//
|
|
// tbscript.cpp
|
|
//
|
|
// This module contains the main data which handles the script interface
|
|
// for the user. All exported APIs are here.
|
|
//
|
|
// Copyright (C) 2001 Microsoft Corporation
|
|
//
|
|
// Author: a-devjen (Devin Jenson)
|
|
//
|
|
|
|
#define INITGUID
|
|
#define _WIN32_DCOM
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <activscp.h>
|
|
#include <olectl.h>
|
|
#include <stddef.h>
|
|
#include <crtdbg.h>
|
|
#include <comcat.h>
|
|
|
|
#include "CTBShell.h"
|
|
#include "CTBGlobal.h"
|
|
#include "CActiveScriptEngine.h"
|
|
#include "tbscript.h"
|
|
#include "scpapi.h"
|
|
#include "resource.h"
|
|
|
|
|
|
#define SCPMODULENAME OLESTR("tbscript.exe")
|
|
|
|
|
|
void SCPGetModuleFileName(void);
|
|
BSTR SCPReadFileAsBSTR(BSTR FileName);
|
|
void SCPFreeBSTR(BSTR Buffer);
|
|
void __cdecl IdleCallback(HANDLE Connection, LPCSTR Text, DWORD Seconds);
|
|
void DummyPrintMessage(MESSAGETYPE MessageType, LPCSTR Format, ...);
|
|
|
|
|
|
static BOOL DLLIsLoaded = FALSE;
|
|
static HMODULE DLLModule;
|
|
static OLECHAR DLLFileName[MAX_PATH];
|
|
|
|
|
|
// Pointers to callbacks, set using the library initialization function
|
|
PFNIDLECALLBACK g_IdleCallback = NULL;
|
|
PFNPRINTMESSAGE g_PrintMessage = NULL;
|
|
|
|
|
|
// Helper class to ease the nesting chaos that comes
|
|
// from the lack of exception support in the C++ language
|
|
// mapping for COM..
|
|
|
|
struct HRESULT_EXCEPTION
|
|
{
|
|
// Default constructor, does nothing
|
|
HRESULT_EXCEPTION() {}
|
|
|
|
// This constructor acts simply as an operator
|
|
// to test a value, and throws an exception
|
|
// if it is invalid.
|
|
HRESULT_EXCEPTION(HRESULT Result) {
|
|
|
|
if (FAILED(Result))
|
|
throw Result;
|
|
}
|
|
|
|
// This is the main attraction of this class.
|
|
// When ever we set an invalid HRESULT, we throw
|
|
// an exception.
|
|
HRESULT operator = (HRESULT Result) {
|
|
|
|
if (FAILED(Result))
|
|
throw Result;
|
|
|
|
return Result;
|
|
}
|
|
};
|
|
|
|
|
|
// DisplayEngines
|
|
//
|
|
// This "HANDLE" is fake for an internal class. It contains references
|
|
// to all objects for a given script instance. These mostly include
|
|
// the script interfaces.
|
|
|
|
|
|
SCPAPI void SCPDisplayEngines(void)
|
|
{
|
|
// get the component category manager for this machine
|
|
ICatInformation *pci = 0;
|
|
unsigned long LanguageCount = 0;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
HRESULT Result = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
|
|
NULL, CLSCTX_SERVER, IID_ICatInformation, (void **)&pci);
|
|
|
|
if (SUCCEEDED(Result)) {
|
|
|
|
// Get the list of parseable script engines
|
|
CATID rgcatidImpl[1];
|
|
rgcatidImpl[0] = CATID_ActiveScriptParse;
|
|
IEnumCLSID *pec = 0;
|
|
Result = pci->EnumClassesOfCategories(1, rgcatidImpl, 0, 0, &pec);
|
|
if (SUCCEEDED(Result))
|
|
{
|
|
// Print the list of CLSIDs to the console as ProgIDs
|
|
enum { CHUNKSIZE = 16 };
|
|
CLSID rgclsid[CHUNKSIZE];
|
|
ULONG cActual;
|
|
do {
|
|
Result = pec->Next(CHUNKSIZE, rgclsid, &cActual);
|
|
if (FAILED(Result))
|
|
break;
|
|
if (Result == S_OK)
|
|
cActual = CHUNKSIZE;
|
|
for (ULONG i = 0; i < cActual; i++) {
|
|
OLECHAR *pwszProgID = 0;
|
|
if (SUCCEEDED(ProgIDFromCLSID(rgclsid[i], &pwszProgID))) {
|
|
printf("%S\n", pwszProgID);
|
|
LanguageCount++;
|
|
CoTaskMemFree(pwszProgID);
|
|
}
|
|
}
|
|
} while (Result != S_FALSE);
|
|
pec->Release();
|
|
|
|
if (LanguageCount == 0)
|
|
printf("%s",
|
|
"ERROR: Windows Scripting Host not installed.\n");
|
|
else
|
|
printf("\n* Total Languages: %lu\n", LanguageCount);
|
|
}
|
|
|
|
else
|
|
printf("ERROR: Failed to retrieve the Class "
|
|
"Enumerator (0x%X).\n", Result);
|
|
pci->Release();
|
|
}
|
|
else
|
|
printf("ERROR: Failed to load the Category Manager (0x%X).\n", Result);
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
|
|
|
|
// CActiveScriptHandle
|
|
//
|
|
// This "HANDLE" is fake for an internal class. It contains references
|
|
// to all objects for a given script instance. These mostly include
|
|
// the script interfaces.
|
|
|
|
class CActiveScriptHandle
|
|
{
|
|
public:
|
|
|
|
// Holds preferred data specified during handle instantiation.
|
|
TSClientData DesiredData;
|
|
|
|
// COM Class pointers...
|
|
CActiveScriptEngine *ActiveScriptEngine;
|
|
IActiveScriptParse *ActiveScriptParse;
|
|
IActiveScript *ActiveScript;
|
|
|
|
// Pointers to the two script instances known as the "TS" object, and
|
|
// the "Global" object for which you do not need to specify the name.
|
|
CTBGlobal *TBGlobal;
|
|
CTBShell *TBShell;
|
|
|
|
// The default user LCID is stored here...
|
|
LCID Lcid;
|
|
|
|
// CActiveScriptHandle::CActiveScriptHandle
|
|
//
|
|
// The constructor. The handle is now being created
|
|
// so use nullify needed pointers, and get other default data.
|
|
//
|
|
// No return value (called internally).
|
|
|
|
CActiveScriptHandle() {
|
|
|
|
// Zero data
|
|
ActiveScriptEngine = NULL;
|
|
ActiveScriptParse = NULL;
|
|
ActiveScript = NULL;
|
|
|
|
ZeroMemory(&DesiredData, sizeof(DesiredData));
|
|
|
|
// Ensure COM is initialized
|
|
CoInitialize(NULL);
|
|
|
|
// Allocate the global object
|
|
TBGlobal = new CTBGlobal;
|
|
|
|
if (TBGlobal == NULL) {
|
|
throw -1;
|
|
}
|
|
// Tell the new object we hold a reference of it
|
|
else {
|
|
TBGlobal->AddRef();
|
|
}
|
|
|
|
// Allocate the shell object
|
|
TBShell = new CTBShell;
|
|
|
|
if (TBShell == NULL) {
|
|
TBGlobal->Release();
|
|
TBGlobal = NULL;
|
|
throw -1;
|
|
}
|
|
// Tell the new object we hold a reference of it
|
|
else {
|
|
TBShell->AddRef();
|
|
}
|
|
|
|
// The global object uses the shell, it needs a reference as well.
|
|
TBGlobal->SetShellObjPtr(TBShell);
|
|
|
|
// Allocate a new engine for the script objects
|
|
ActiveScriptEngine = new CActiveScriptEngine(TBGlobal, TBShell);
|
|
|
|
if (ActiveScriptEngine == NULL) {
|
|
TBGlobal->Release();
|
|
TBGlobal = NULL;
|
|
TBShell->Release();
|
|
TBShell = NULL;
|
|
throw -1;
|
|
}
|
|
|
|
// Tell the script engine we hold a reference of it
|
|
ActiveScriptEngine->AddRef();
|
|
|
|
// Record the default user LCID
|
|
Lcid = GetUserDefaultLCID();
|
|
|
|
// And finally, record this script engine on the global object
|
|
// for recursive scripting...
|
|
// (The user can LoadScript() more scripts)
|
|
TBGlobal->SetScriptEngine((HANDLE)this);
|
|
}
|
|
|
|
// CActiveScriptHandle::~CActiveScriptHandle
|
|
//
|
|
// The destructor. The handle being closed, remove references.
|
|
//
|
|
// No return value (called internally).
|
|
|
|
~CActiveScriptHandle() {
|
|
|
|
// First off we need to release the main IDispatch of
|
|
// the IActiveScript interface.
|
|
if (ActiveScript != NULL) {
|
|
|
|
IDispatch *Dispatch = NULL;
|
|
|
|
// Query the to get the reference
|
|
HRESULT Result = ActiveScript->GetScriptDispatch(0, &Dispatch);
|
|
|
|
// And release it
|
|
if (SUCCEEDED(Result) && Dispatch != NULL)
|
|
|
|
Dispatch->Release();
|
|
|
|
ActiveScript = NULL;
|
|
}
|
|
|
|
// The main script engine first of all, to unbind it.
|
|
if (ActiveScriptEngine != NULL) {
|
|
|
|
ActiveScriptEngine->Release();
|
|
ActiveScriptEngine = NULL;
|
|
}
|
|
|
|
// Now release the parser
|
|
if (ActiveScriptParse != NULL) {
|
|
|
|
ActiveScriptParse->Release();
|
|
ActiveScriptParse = NULL;
|
|
}
|
|
|
|
// And the main IActiveScript interface itself.
|
|
if (ActiveScript != NULL) {
|
|
|
|
ActiveScript->Release();
|
|
ActiveScript = NULL;
|
|
}
|
|
|
|
// The global scripting object
|
|
if (TBGlobal != NULL) {
|
|
|
|
TBGlobal->Release();
|
|
TBGlobal = NULL;
|
|
}
|
|
|
|
// Finally, the shell or "TS" object.
|
|
if (TBShell != NULL) {
|
|
|
|
TBShell->Release();
|
|
TBShell = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// TODO: UPDATE THIS FUNCTION WHEN TBSCRIPT BECOMES
|
|
// OCX OR A COM COMPATIBLE HOST.
|
|
//
|
|
// SCPGetModuleFileName
|
|
//
|
|
// This routine gets the handle to the TBScript module.
|
|
// Additionally it also gets the full path where the
|
|
// module is located on disk. Due to the nature of the
|
|
// call, the variables are held globally, they are called:
|
|
// DLLFileName and DLLModule. The function only needs to
|
|
// be called once, but additional calls are safe and
|
|
// will be silently ignored.
|
|
|
|
void SCPGetModuleFileName(void)
|
|
{
|
|
// Check to see if we already have done this procedure
|
|
if (DLLIsLoaded == FALSE) {
|
|
|
|
// First get the handle
|
|
DLLModule = GetModuleHandleW(SCPMODULENAME);
|
|
|
|
// Now copy the file name
|
|
GetModuleFileNameW(DLLModule, DLLFileName, MAX_PATH);
|
|
|
|
// Indicate we have done this call already
|
|
DLLIsLoaded = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// SCPLoadTypeInfoFromThisModule
|
|
//
|
|
// This loads the OLE code held in a resource of this very module.
|
|
//
|
|
// Returns an HRESULT value.
|
|
|
|
HRESULT SCPLoadTypeInfoFromThisModule(REFIID RefIID, ITypeInfo **TypeInfo)
|
|
{
|
|
HRESULT Result;
|
|
ITypeLib *TypeLibrary = NULL;
|
|
|
|
// Ensure we have the handle to the module first
|
|
SCPGetModuleFileName();
|
|
|
|
// Use the API now to load the entire TypeLib
|
|
Result = LoadTypeLib(DLLFileName, &TypeLibrary);
|
|
|
|
// We shouldn't fail, but be prepared...
|
|
_ASSERT(SUCCEEDED(Result));
|
|
|
|
// If we succeeded we have more to do
|
|
if (SUCCEEDED(Result)) {
|
|
|
|
// Nullify the pointer
|
|
*TypeInfo = NULL;
|
|
|
|
// In this TypeLib, grab the TypeInfo data
|
|
Result = TypeLibrary->GetTypeInfoOfGuid(RefIID, TypeInfo);
|
|
|
|
// We now have the TypeInfo, and we don't need the TypeLib
|
|
// anymore, so release it.
|
|
TypeLibrary->Release();
|
|
|
|
if (Result == E_OUTOFMEMORY)
|
|
Result = TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
|
|
// SCPReadFileAsBSTR
|
|
//
|
|
// Takes a script filename, reads it into COM allocated memory.
|
|
// Don't forget to call SCPFreeBSTR() when done!
|
|
//
|
|
// Returns a pointer to the allocated object is returned
|
|
// on success, or NULL on failure.
|
|
|
|
BSTR SCPReadFileAsBSTR(BSTR FileName)
|
|
{
|
|
BSTR Result = NULL;
|
|
|
|
// Open the file
|
|
HANDLE File = CreateFileW(FileName, GENERIC_READ, FILE_SHARE_READ,
|
|
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
// Sanity check
|
|
if (File != INVALID_HANDLE_VALUE) {
|
|
|
|
// Get the file size
|
|
DWORD FileSize = GetFileSize(File, 0);
|
|
|
|
// Allocate a block on the local heap to read the file to
|
|
char *MemBlock = (char *)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY, FileSize + 1);
|
|
|
|
// This really shouldn't happen
|
|
_ASSERT(MemBlock != NULL);
|
|
|
|
// Sanity check again
|
|
if (MemBlock != NULL) {
|
|
|
|
// Read the file into memory
|
|
DWORD ReadCount;
|
|
|
|
if ( ReadFile(File, MemBlock, FileSize, &ReadCount, 0) ) {
|
|
|
|
// Allocate task memory block
|
|
Result = (BSTR)CoTaskMemAlloc(sizeof(OLECHAR) * (FileSize + 1));
|
|
|
|
// Copy from our old buffer to the new one
|
|
if (Result != NULL) {
|
|
|
|
// Convert to wide-character on the new buffer
|
|
mbstowcs(Result, MemBlock, FileSize + 1);
|
|
|
|
// Ensure string termination.
|
|
Result[FileSize] = 0;
|
|
}
|
|
}
|
|
|
|
// Free the temporary ASCII memory block
|
|
HeapFree(GetProcessHeap(), 0, MemBlock);
|
|
}
|
|
|
|
// Close the file
|
|
CloseHandle(File);
|
|
}
|
|
|
|
// Tell the user this failed in debug mode
|
|
_ASSERT(File != INVALID_HANDLE_VALUE);
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
// SCPFreeBSTR
|
|
//
|
|
// This function is really a wrapper for releasing task memory blocks
|
|
// obtained through the function ReadFileAsBSTR
|
|
//
|
|
// No return value.
|
|
|
|
void SCPFreeBSTR(BSTR Buffer)
|
|
{
|
|
CoTaskMemFree(Buffer);
|
|
}
|
|
|
|
|
|
// SCPNewScriptEngine
|
|
//
|
|
// Allocates and initializes a new script engine.
|
|
//
|
|
// Returns a handle to the new engine, or NULL on failure.
|
|
|
|
HANDLE SCPNewScriptEngine(BSTR LangName,
|
|
TSClientData *DesiredData, LPARAM lParam)
|
|
{
|
|
CActiveScriptHandle *ActiveScriptHandle = NULL;
|
|
|
|
try {
|
|
|
|
HRESULT_EXCEPTION Result;
|
|
CLSID ClassID;
|
|
|
|
// Allocate a new handle
|
|
ActiveScriptHandle = new CActiveScriptHandle();
|
|
|
|
if (ActiveScriptHandle == NULL)
|
|
return NULL;
|
|
|
|
// Much of the initialization has already been done now.. but
|
|
// not enough, we have to manually set some stuff.
|
|
|
|
// Record the user desired data
|
|
ActiveScriptHandle->TBGlobal->SetPrintMessage(g_PrintMessage);
|
|
ActiveScriptHandle->TBShell->SetDesiredData(DesiredData);
|
|
ActiveScriptHandle->TBShell->SetParam(lParam);
|
|
|
|
// Get the class ID of the language
|
|
Result = CLSIDFromProgID(LangName, &ClassID);
|
|
|
|
// Create an instance of the script parser
|
|
Result = CoCreateInstance(ClassID, NULL, CLSCTX_ALL,
|
|
IID_IActiveScriptParse,
|
|
(void **)&(ActiveScriptHandle->ActiveScriptParse));
|
|
|
|
// Get the IActiveScript interface
|
|
Result = ActiveScriptHandle->ActiveScriptParse->
|
|
QueryInterface(IID_IActiveScript,
|
|
(void **)&(ActiveScriptHandle->ActiveScript));
|
|
|
|
// Set script state to INITIALIZED
|
|
Result = ActiveScriptHandle->ActiveScriptParse->InitNew();
|
|
|
|
// Bind our custom made "ActiveScriptSite" to the
|
|
// ActiveScript interface
|
|
Result = ActiveScriptHandle->ActiveScript->
|
|
SetScriptSite(ActiveScriptHandle->ActiveScriptEngine);
|
|
|
|
// Add the shell and global objects to engine's
|
|
// namespace and set state to STARTED
|
|
Result = ActiveScriptHandle->ActiveScript->
|
|
AddNamedItem(OLESTR("TS"),
|
|
SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE);
|
|
|
|
Result = ActiveScriptHandle->ActiveScript->
|
|
AddNamedItem(OLESTR("Global"), SCRIPTITEM_ISVISIBLE |
|
|
SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS);
|
|
|
|
// And globally connect this new script engine
|
|
Result = ActiveScriptHandle->ActiveScript->
|
|
SetScriptState(SCRIPTSTATE_CONNECTED);
|
|
}
|
|
|
|
// Our handy HRESULT = operator will catch any errors here
|
|
catch (HRESULT Result) {
|
|
|
|
Result = 0;
|
|
|
|
// If the handle is still active, delete it
|
|
if(ActiveScriptHandle != NULL)
|
|
delete ActiveScriptHandle;
|
|
|
|
// Return error
|
|
return NULL;
|
|
}
|
|
|
|
// Return the handle
|
|
return (HANDLE)ActiveScriptHandle;
|
|
}
|
|
|
|
|
|
// SCPRunScript
|
|
//
|
|
// Takes a file, and runs it as a script. This will only
|
|
// return when the script has finished executing.
|
|
//
|
|
// Returns TRUE if the script completed successfully,
|
|
// FALSE otherwise.
|
|
|
|
SCPAPI BOOL SCPRunScript(BSTR LangName, BSTR FileName,
|
|
TSClientData *DesiredData, LPARAM lParam)
|
|
{
|
|
HANDLE EngineHandle;
|
|
|
|
// First read the file into memory. We allocate here instead of
|
|
// calling SCPParseScriptFile in one shot because if the allocation
|
|
// fails, there is no reason to create a script engine, which in
|
|
// this case it won't.
|
|
BSTR Code = SCPReadFileAsBSTR(FileName);
|
|
|
|
if (Code == NULL)
|
|
return FALSE;
|
|
|
|
// Next create the script control
|
|
EngineHandle = SCPNewScriptEngine(LangName, DesiredData, lParam);
|
|
|
|
if (EngineHandle == NULL) {
|
|
|
|
SCPFreeBSTR(Code);
|
|
return FALSE;
|
|
}
|
|
|
|
// Parse the script into the engine
|
|
if (SCPParseScript(EngineHandle, Code) == FALSE) {
|
|
|
|
SCPFreeBSTR(Code);
|
|
return FALSE;
|
|
}
|
|
|
|
// Success, free the script code
|
|
SCPFreeBSTR(Code);
|
|
|
|
// Close the script engine
|
|
SCPCloseScriptEngine(EngineHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// SCPParseScriptFile
|
|
//
|
|
// Takes a file, reads it into memory, and parses it into the script engine.
|
|
// This function only returns when the parsing has completed.
|
|
//
|
|
// Returns TRUE on success, or FALSE on failure.
|
|
|
|
BOOL SCPParseScriptFile(HANDLE EngineHandle, BSTR FileName)
|
|
{
|
|
// First read the file into memory
|
|
BSTR Code = SCPReadFileAsBSTR(FileName);
|
|
|
|
if(Code == NULL)
|
|
return FALSE;
|
|
|
|
// Next parse it
|
|
if(SCPParseScript(EngineHandle, Code) == FALSE) {
|
|
|
|
SCPFreeBSTR(Code);
|
|
return FALSE;
|
|
}
|
|
|
|
SCPFreeBSTR(Code);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// SCPParseScript
|
|
//
|
|
// Reads a script in memory, and parses it into the script engine.
|
|
// This function only returns when the parsing has completed.
|
|
//
|
|
// Returns TRUE on success, or FALSE on failure.
|
|
|
|
BOOL SCPParseScript(HANDLE EngineHandle, BSTR Script)
|
|
{
|
|
// First cast the engine handle over to something we can use
|
|
CActiveScriptHandle *ActiveScriptHandle =
|
|
(CActiveScriptHandle *)EngineHandle;
|
|
|
|
HRESULT Result = E_FAIL;
|
|
|
|
// Make exception data
|
|
EXCEPINFO ExceptInfo = { 0 };
|
|
|
|
// Parse the script using the ActiveScript API
|
|
Result = ActiveScriptHandle->ActiveScriptParse->ParseScriptText(Script,
|
|
0, 0, 0, 0, 0,
|
|
SCRIPTTEXT_ISPERSISTENT | SCRIPTTEXT_ISVISIBLE,
|
|
0, &ExceptInfo);
|
|
|
|
return SUCCEEDED(Result);
|
|
}
|
|
|
|
|
|
// SCPCloseScriptEngine
|
|
//
|
|
// Closes a script handle simply by deleting it.
|
|
//
|
|
// No return value.
|
|
|
|
void SCPCloseScriptEngine(HANDLE EngineHandle)
|
|
{
|
|
// First cast the engine handle over to something we can use
|
|
CActiveScriptHandle *ActiveScriptHandle =
|
|
(CActiveScriptHandle *)EngineHandle;
|
|
|
|
// Release it from memory.. the deconstructor does all the work.
|
|
if (ActiveScriptHandle != NULL)
|
|
delete ActiveScriptHandle;
|
|
}
|
|
|
|
|
|
// SCPCleanupLibrary
|
|
//
|
|
// This should only be called when all script engines are unloaded
|
|
// and the module is going to be uninitialized.
|
|
//
|
|
// No return value.
|
|
|
|
SCPAPI void SCPCleanupLibrary(void)
|
|
{
|
|
CoUninitialize();
|
|
|
|
g_IdleCallback = NULL;
|
|
}
|
|
|
|
|
|
// SCPStartupLibrary
|
|
//
|
|
// Simply initializes the library, setting up the callback routine.
|
|
// This should be called before using any other script procedures.
|
|
//
|
|
// No return value.
|
|
|
|
SCPAPI void SCPStartupLibrary(SCINITDATA *InitData,
|
|
PFNIDLECALLBACK fnIdleCallback)
|
|
{
|
|
// Record our idle callback function
|
|
g_IdleCallback = fnIdleCallback;
|
|
|
|
if(InitData != NULL) {
|
|
|
|
__try {
|
|
|
|
// Record the print message function in the InitData structure
|
|
if(InitData != NULL)
|
|
g_PrintMessage = InitData->pfnPrintMessage;
|
|
}
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
// Bad pointer, simply initialize T2Client with our own
|
|
// callback then.
|
|
SCINITDATA LibInitData = { DummyPrintMessage };
|
|
|
|
T2Init(&LibInitData, IdleCallback);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Initialize with T2Client now.
|
|
T2Init(InitData, IdleCallback);
|
|
}
|
|
|
|
|
|
// IdleCallback
|
|
//
|
|
// This is an internal wrapping callback procedure used
|
|
// for redirecting idle messages.
|
|
//
|
|
// No return value.
|
|
|
|
void __cdecl IdleCallback(HANDLE Connection, LPCSTR Text, DWORD Seconds)
|
|
{
|
|
LPARAM lParam = 0;
|
|
|
|
// Get the parameter for the connection, and pass it back to the user
|
|
if (g_IdleCallback != NULL && T2GetParam(Connection, &lParam) == NULL)
|
|
|
|
g_IdleCallback(lParam, Text, Seconds);
|
|
}
|
|
|
|
|
|
// DummyPrintMessage
|
|
//
|
|
// Filler in case the user messes up.
|
|
//
|
|
// No return value.
|
|
|
|
void DummyPrintMessage(MESSAGETYPE MessageType, LPCSTR Format, ...)
|
|
{
|
|
return;
|
|
}
|