|
|
#include "precomp.h"
//
// Application Loader
//
#define MLZ_FILE_ZONE ZONE_OM
//
// ALP_Init()
//
BOOL ALP_Init(BOOL * pfCleanup) { BOOL fInit = FALSE;
DebugEntry(ALP_Init);
UT_Lock(UTLOCK_AL);
if (g_putAL || g_palPrimary) { *pfCleanup = FALSE; ERROR_OUT(("Can't start AL primary task; already running")); DC_QUIT; } else { //
// From this point on, there is cleanup to do.
//
*pfCleanup = TRUE; }
//
// Register AL task
//
if (!UT_InitTask(UTTASK_AL, &g_putAL)) { ERROR_OUT(("Failed to start AL task")); DC_QUIT; }
//
// Allocate PRIMARY data
//
g_palPrimary = (PAL_PRIMARY)UT_MallocRefCount(sizeof(AL_PRIMARY), TRUE); if (!g_palPrimary) { ERROR_OUT(("Failed to allocate AL memory block")); DC_QUIT; }
SET_STAMP(g_palPrimary, ALPRIMARY); g_palPrimary->putTask = g_putAL;
//
// Register an exit and event proc
//
UT_RegisterExit(g_putAL, ALPExitProc, g_palPrimary); g_palPrimary->exitProcRegistered = TRUE;
UT_RegisterEvent(g_putAL, ALPEventProc, g_palPrimary, UT_PRIORITY_NORMAL); g_palPrimary->eventProcRegistered = TRUE;
if (!CMS_Register(g_putAL, CMTASK_AL, &g_palPrimary->pcmClient)) { ERROR_OUT(("Could not register ALP with CMS")); DC_QUIT; }
//
// Register as an OBMAN Secondary task (call OM_Register())
//
if (OM_Register(g_putAL, OMCLI_AL, &g_palPrimary->pomClient) != 0) { ERROR_OUT(( "Could not register ALP with OBMAN")); DC_QUIT; }
fInit = TRUE;
DC_EXIT_POINT: UT_Unlock(UTLOCK_AL);
DebugExitBOOL(ALP_Init, fInit); return(fInit); }
//
// ALP_Term()
//
void ALP_Term(void) { DebugEntry(ALP_Term);
UT_Lock(UTLOCK_AL);
if (g_palPrimary) { ValidateALP(g_palPrimary);
ValidateUTClient(g_putAL);
//
// Deregister from Call Manager (if registered call CM_Deregister())
//
if (g_palPrimary->pcmClient) { CMS_Deregister(&g_palPrimary->pcmClient); }
//
// Deregister from OBMAN (if registered call OM_Deregister())
//
if (g_palPrimary->pomClient) { OM_Deregister(&g_palPrimary->pomClient); }
//
// Do our own task termination
//
ALPExitProc(g_palPrimary); }
UT_TermTask(&g_putAL);
UT_Unlock(UTLOCK_AL);
DebugExitVOID(ALP_Term); }
//
// ALPExitProc()
//
void CALLBACK ALPExitProc(LPVOID data) { PAL_PRIMARY palPrimary = (PAL_PRIMARY)data; UINT i;
DebugEntry(ALPExitProc);
UT_Lock(UTLOCK_AL);
ValidateALP(palPrimary); ASSERT(palPrimary == g_palPrimary);
//
// Deregister event procedure
//
if (palPrimary->eventProcRegistered) { UT_DeregisterEvent(g_putAL, ALPEventProc, palPrimary); palPrimary->eventProcRegistered = FALSE; }
//
// Deregister exit procedure (if registered call UT_DeregisterExit()
//
if (palPrimary->exitProcRegistered) { UT_DeregisterExit(g_putAL, ALPExitProc, palPrimary); palPrimary->exitProcRegistered = FALSE; }
//
// Free memory
//
UT_FreeRefCount((void**)&g_palPrimary, TRUE);
UT_Unlock(UTLOCK_AL);
DebugExitVOID(ALPExitProc); }
//
// ALPEventProc()
//
BOOL CALLBACK ALPEventProc ( LPVOID data, UINT event, UINT_PTR param1, UINT_PTR param2 ) { PAL_PRIMARY palPrimary = (PAL_PRIMARY)data; BOOL processed = FALSE;
DebugEntry(ALPEventProc);
UT_Lock(UTLOCK_AL);
ValidateALP(palPrimary);
switch (event) { case AL_INT_RETRY_NEW_CALL: // Retry new call
ALNewCall(palPrimary, (UINT)param1, (UINT)param2); processed = TRUE; break;
case CMS_NEW_CALL: // First try new call
ALNewCall(palPrimary, AL_NEW_CALL_RETRY_COUNT, (UINT)param2); break;
case CMS_END_CALL: ALEndCall(palPrimary, (UINT)param2); break;
case OM_WSGROUP_REGISTER_CON: ALWorksetRegisterCon(palPrimary, ((POM_EVENT_DATA32)¶m2)->correlator, ((POM_EVENT_DATA32)¶m2)->result, ((POM_EVENT_DATA16)¶m1)->hWSGroup); break;
case OM_WORKSET_OPEN_CON: if ((((POM_EVENT_DATA16)¶m1)->hWSGroup == palPrimary->alWSGroupHandle) && (((POM_EVENT_DATA16)¶m1)->worksetID == 0) && (((POM_EVENT_DATA32)¶m2)->result == 0) ) { TRACE_OUT(( "OM_WORKSET_OPEN_CON OK for AL workset 0")); palPrimary->alWorksetOpen = TRUE;
if (palPrimary->alWBRegPend) ALLocalLoadResult(palPrimary, (palPrimary->alWBRegSuccess != FALSE)); } break;
case OM_WORKSET_NEW_IND: if (ALWorksetNewInd(palPrimary, ((POM_EVENT_DATA16)¶m1)->hWSGroup, ((POM_EVENT_DATA16)¶m1)->worksetID)) { //
// The event was for a workset the Application Loader was
// expecting - don't pass it on
//
processed = TRUE; } break;
case OM_OBJECT_ADD_IND: //
// See if it is a new workset group in an OBMAN control workset
// (call ALNewWorksetGroup())
//
// If it isn't then see if it is a load result in the
// Application Loader result workset (call ALRemoteLoadResult())
//
//
TRACE_OUT(( "OM_OBJECT_ADD_IND"));
if (ALNewWorksetGroup(palPrimary, ((POM_EVENT_DATA16)¶m1)->hWSGroup, (POM_OBJECT)param2)) { //
// OBJECT_ADD was for an OBMAN control workset object Don't
// pass event on to other handlers.
//
TRACE_OUT(("OBJECT_ADD was for OBMAN workset group")); processed = TRUE; } else { if (ALRemoteLoadResult(palPrimary, ((POM_EVENT_DATA16)¶m1)->hWSGroup, (POM_OBJECT)param2)) { //
// OBJECT_ADD was for an AL remote result workset
// object Don't pass event on to other handlers.
//
TRACE_OUT(("OBJECT_ADD was for AL workset group")); processed = TRUE; } } break;
case OM_WORKSET_CLEAR_IND: TRACE_OUT(( "OM_WORKSET_CLEAR_IND"));
if (palPrimary->alWSGroupHandle == ((POM_EVENT_DATA16)¶m1)->hWSGroup) { TRACE_OUT(( "Confirming OM_WORKSET_CLEAR_IND event")); OM_WorksetClearConfirm(palPrimary->pomClient, ((POM_EVENT_DATA16)¶m1)->hWSGroup, ((POM_EVENT_DATA16)¶m1)->worksetID); } break;
case OM_OBJECT_DELETE_IND: if (palPrimary->alWSGroupHandle == ((POM_EVENT_DATA16)¶m1)->hWSGroup) { OM_ObjectDeleteConfirm(palPrimary->pomClient, ((POM_EVENT_DATA16)¶m1)->hWSGroup, ((POM_EVENT_DATA16)¶m1)->worksetID, (POM_OBJECT)param2); } break;
case OM_OBJECT_REPLACE_IND: if (palPrimary->alWSGroupHandle == ((POM_EVENT_DATA16)¶m1)->hWSGroup) { OM_ObjectReplaceConfirm(palPrimary->pomClient, ((POM_EVENT_DATA16)¶m1)->hWSGroup, ((POM_EVENT_DATA16)¶m1)->worksetID, (POM_OBJECT)param2); } break;
case OM_OBJECT_UPDATE_IND: if (palPrimary->alWSGroupHandle == ((POM_EVENT_DATA16)¶m1)->hWSGroup) { OM_ObjectUpdateConfirm(palPrimary->pomClient, ((POM_EVENT_DATA16)¶m1)->hWSGroup, ((POM_EVENT_DATA16)¶m1)->worksetID, (POM_OBJECT)param2); } break;
case AL_INT_STARTSTOP_WB: ALStartStopWB(palPrimary, (LPCTSTR)param2); processed = TRUE; break;
default: break; }
UT_Unlock(UTLOCK_AL);
DebugExitBOOL(ALPEventProc, processed); return(processed); }
//
// ALNewCall()
//
void ALNewCall ( PAL_PRIMARY palPrimary, UINT retryCount, UINT callID ) { UINT rc; OM_WSGROUP_HANDLE hWSGroup; CM_STATUS status;
DebugEntry(ALNewCall);
ValidateALP(palPrimary);
//
// Can we handle a new call?
//
if (palPrimary->inCall) { WARNING_OUT(("No more room for calls")); DC_QUIT; }
//
// Is ObMan/AppLoader/OldWB disabled for this call?
//
CMS_GetStatus(&status); if (!(status.attendeePermissions & NM_PERMIT_USEOLDWBATALL)) { WARNING_OUT(("Joining Meeting with no OLDWB AL at all")); DC_QUIT; }
//
// Register as a secondary with the OBMAN workset group for the new
// call:
//
rc = OM_WSGroupRegisterS(palPrimary->pomClient, callID, OMFP_OM, OMWSG_OM, &hWSGroup);
if ((rc == OM_RC_NO_PRIMARY) && (retryCount > 0)) { //
// Although a call has started, ObMan hasn't joined it yet - we
// must have got the NEW_CALL event before it did. So, we'll try
// again after a short delay.
//
// Note that we cannot post the CMS_NEW_CALL event itself back to
// ourselves, because it is bad programming practice to post other
// people's events (e.g. CM could register a hidden handler which
// performs some non-repeatable operation on receipt of one of its
// events).
//
// Therefore, we post an internal AL event which we treat in the
// same way.
//
// To avoid retry forever, we use the first parameter of the event
// as a countdown retry count. The first time this function is
// called (on receipt of a genuine CMS_NEW_CALL) the count is set
// to the default. Each time we post a delay event, we decrement
// the value passed in and post that as param1. When it hits zero,
// we give up.
//
TRACE_OUT(("Got OM_RC_NO_PRIMARY from 2nd reg for call %d, %d retries left", callID, retryCount));
UT_PostEvent(palPrimary->putTask, palPrimary->putTask, AL_RETRY_DELAY, AL_INT_RETRY_NEW_CALL, --retryCount, callID); DC_QUIT; }
if (rc) // includes NO_PRIMARY when retry count == 0
{ //
// If we get any other error (or NO_PRIMARY when the retry count is
// zero, it's more serious:
//
// lonchanc: was ERROR_OUT (happened when hang up immediately place a call)
WARNING_OUT(( "Error registering with obman WSG, rc = %#x", rc)); DC_QUIT; }
TRACE_OUT(("Registered as OBMANCONTROL secondary in call %d", callID));
//
// Record the call ID and the correlator in the call information in
// primary task memory
//
palPrimary->inCall = TRUE; palPrimary->omWSGroupHandle = hWSGroup; palPrimary->callID = callID; palPrimary->alWSGroupHandle = 0;
//
// Now we want to open workset #0 in the OBMAN workset group, but it
// mightn't exist yet. As soon as it is created, we will get a
// WORKSET_NEW event, so we wait (asynchronously) for that.
//
//
// Now that we have opened the OBMAN workset group, we shall register
// with the application loader workset group
//
if (OM_WSGroupRegisterPReq(palPrimary->pomClient, callID, OMFP_AL, OMWSG_AL, &palPrimary->omWSGCorrelator) != 0) { ERROR_OUT(( "Could not register AL workset group")); }
DC_EXIT_POINT: DebugExitVOID(ALNewCall); }
//
// ALEndCall()
//
void ALEndCall ( PAL_PRIMARY palPrimary, UINT callID ) { UINT i;
DebugEntry(ALEndCall);
ValidateALP(palPrimary);
//
// See if we have information for this call
//
if (!palPrimary->inCall || (palPrimary->callID != callID)) { //
// Not an error - we may not have joined the call yet.
//
TRACE_OUT(("Unexpected call %d", callID)); DC_QUIT; }
//
// Deregister from the OBMAN workset group for the call (if registered
// call OM_WSGroupDeregister())
//
if (palPrimary->omWSGroupHandle) { OM_WSGroupDeregister(palPrimary->pomClient, &palPrimary->omWSGroupHandle); ASSERT(palPrimary->omWSGroupHandle == 0); }
//
// Deregister from the AL workset group for the call (if registered
// call OM_WSGroupDeregister())
//
if (palPrimary->alWSGroupHandle) { OM_WSGroupDeregister(palPrimary->pomClient, &palPrimary->alWSGroupHandle); ASSERT(palPrimary->alWSGroupHandle == 0); }
//
// Clear out all our call state variables
//
palPrimary->inCall = FALSE; palPrimary->omWSGCorrelator = 0; palPrimary->callID = 0; palPrimary->omWSCorrelator = 0; palPrimary->omUID = 0; palPrimary->alWorksetOpen = FALSE; palPrimary->alWBRegPend = FALSE;
DC_EXIT_POINT: DebugExitVOID(ALEndCall); }
//
// ALWorksetNewInd()
//
BOOL ALWorksetNewInd ( PAL_PRIMARY palPrimary, OM_WSGROUP_HANDLE hWSGroup, OM_WORKSET_ID worksetID ) { BOOL fHandled = FALSE;
DebugEntry(ALWorksetNewInd);
ValidateALP(palPrimary);
if (worksetID != 0) { TRACE_OUT(( "Workset ID is %u, ignoring and passing event on", worksetID)); DC_QUIT; }
if (!palPrimary->inCall || (palPrimary->omWSGroupHandle != hWSGroup)) { TRACE_OUT(("Got WORKSET_NEW_IND for WSG %d, but not in call", hWSGroup)); DC_QUIT; }
//
// Now open the workset (secondary Open, so synchronous):
//
if (OM_WorksetOpenS(palPrimary->pomClient, palPrimary->omWSGroupHandle, 0) != 0) { ERROR_OUT(( "Error opening OBMAN control workset")); palPrimary->inCall = FALSE; DC_QUIT; }
TRACE_OUT(("Opened OBMANCONTROL workset #0 in call %d", palPrimary->callID));
fHandled = TRUE;
DC_EXIT_POINT: DebugExitBOOL(ALWorksetNewInd, fHandled); return(fHandled); }
//
// ALNewWorksetGroup()
//
BOOL ALNewWorksetGroup ( PAL_PRIMARY palPrimary, OM_WSGROUP_HANDLE omWSGroup, POM_OBJECT pObj ) { BOOL fHandled = FALSE; POM_OBJECTDATA pData = NULL; OM_WSGROUP_INFO WSGInfo; OMFP fpHandler; BOOL fLoaded;
DebugEntry(ALNewWorksetGroup);
ValidateALP(palPrimary);
//
// If the workset group is not in out list of calls, then this event
// is for a group the Application Loader has registered with. The
// event should be passed onto other event procedures.
//
if (!palPrimary->inCall || (palPrimary->omWSGroupHandle != omWSGroup)) { TRACE_OUT(("WSG 0x%x not the OBMAN WSG", omWSGroup)); DC_QUIT; }
//
// This event is for us
//
fHandled = TRUE;
//
// If the workset group was not created locally
//
TRACE_OUT(("About to read object 0x%08x in OMC", pObj));
if (OM_ObjectRead(palPrimary->pomClient, omWSGroup, 0, pObj, &pData) != 0) { ERROR_OUT(( "Could not access object")); DC_QUIT; }
//
// Take a copy of the information so we can release the object straight
// away
//
memcpy(&WSGInfo, pData, min(sizeof(WSGInfo), pData->length));
//
// Release the object
//
OM_ObjectRelease(palPrimary->pomClient, omWSGroup, 0, pObj, &pData);
if (WSGInfo.idStamp != OM_WSGINFO_ID_STAMP) { TRACE_OUT(( "Not WSG Info - ignoring")); DC_QUIT; }
TRACE_OUT(("New WSG FP %s, name %s, ID = 0x%08x in call %d", WSGInfo.functionProfile, WSGInfo.wsGroupName, WSGInfo.wsGroupID, palPrimary->callID));
//
// Store the UID for the local OBMAN in the new call
//
if (!palPrimary->omUID) { OM_GetNetworkUserID(palPrimary->pomClient, omWSGroup, &(palPrimary->omUID)); }
//
// Ignore workset groups created by the local machine
//
if (WSGInfo.creator == palPrimary->omUID) { TRACE_OUT(("WSG %s created locally - ignoring", WSGInfo.functionProfile)); DC_QUIT; }
//
// Is this a workset we care about? I.E. not a backlevel clipboard
// or whatever thing.
//
fpHandler = OMMapNameToFP(WSGInfo.functionProfile);
if (fpHandler != OMFP_WB) { //
// We don't care about this one.
//
TRACE_OUT(("Obsolete workset %s from another party", WSGInfo.functionProfile)); DC_QUIT; }
//
// If prevented by policy, don't launch it either.
//
if (g_asPolicies & SHP_POLICY_NOOLDWHITEBOARD) { WARNING_OUT(("Failing auto-launch of old whiteboard; prevented by policy")); } else { // Old whiteboard...
fLoaded = ALStartStopWB(palPrimary, NULL); ALLocalLoadResult(palPrimary, fLoaded); }
DC_EXIT_POINT: DebugExitBOOL(ALNewWorksetGroup, fHandled); return(fHandled); }
//
// ALLocalLoadResult()
//
void ALLocalLoadResult ( PAL_PRIMARY palPrimary, BOOL success ) { PTSHR_AL_LOAD_RESULT pAlLoadObject; POM_OBJECT pObjNew; POM_OBJECTDATA pDataNew; CM_STATUS cmStatus;
DebugEntry(ALLocalLoadResult);
//
// Have we accessed the workset correctly yet?
//
if (!palPrimary->alWorksetOpen && palPrimary->inCall) { TRACE_OUT(("AL Workset not open yet; deferring local load result"));
palPrimary->alWBRegPend = TRUE; palPrimary->alWBRegSuccess = (success != FALSE);
DC_QUIT; }
//
// Clear out pending reg stuff
//
palPrimary->alWBRegPend = FALSE;
//
// Create an object to be used to inform remote sites of the result of
// the load.
//
if (OM_ObjectAlloc(palPrimary->pomClient, palPrimary->alWSGroupHandle, 0, sizeof(*pAlLoadObject), &pDataNew) != 0) { ERROR_OUT(("Could not allocate AL object for WB load")); DC_QUIT; }
//
// Fill in information about object
//
pDataNew->length = sizeof(*pAlLoadObject); pAlLoadObject = (PTSHR_AL_LOAD_RESULT)pDataNew->data;
//
// HERE'S WHERE WE MAP the FP constant back to a string
//
lstrcpy(pAlLoadObject->szFunctionProfile, OMMapFPToName(OMFP_WB));
CMS_GetStatus(&cmStatus); lstrcpy(pAlLoadObject->personName, cmStatus.localName); pAlLoadObject->result = (success ? AL_LOAD_SUCCESS : AL_LOAD_FAIL_BAD_EXE);
//
// Add object to Application Loader workset
//
if (OM_ObjectAdd(palPrimary->pomClient, palPrimary->alWSGroupHandle, 0, &pDataNew, 0, &pObjNew, LAST) != 0) { ERROR_OUT(("Could not add WB load object to AL WSG"));
//
// Free object
//
OM_ObjectDiscard(palPrimary->pomClient, palPrimary->alWSGroupHandle, 0, &pDataNew); DC_QUIT; }
//
// Now that we have added the object - lets delete it!
//
// This may sound strange, but every application that has this workset
// open will receive OBJECT_ADD events and be able to read the object
// before they confirm the delete. This means that all the Application
// Loader primary tasks in the call will be able to record the result
// of this attempted load.
//
// Deleting the object here is the simplest way of tidying up the
// workset.
//
OM_ObjectDelete(palPrimary->pomClient, palPrimary->alWSGroupHandle, 0, pObjNew);
DC_EXIT_POINT: DebugExitVOID(ALLocalLoadResult); }
//
// ALWorksetRegister()
//
void ALWorksetRegisterCon ( PAL_PRIMARY palPrimary, UINT correlator, UINT result, OM_WSGROUP_HANDLE hWSGroup ) { DebugEntry(ALWorksetRegisterCon);
ValidateALP(palPrimary);
//
// See if this an event for the Application Loader function profile
//
if (!palPrimary->inCall || (palPrimary->omWSGCorrelator != correlator)) { TRACE_OUT(( "OM_WSGROUP_REGISTER_CON not for us")); DC_QUIT; }
palPrimary->omWSGCorrelator = 0;
//
// Store the workset group handle if the registration was successful
//
if (result) { WARNING_OUT(("Could not register with AL function profile, %#hx", result)); DC_QUIT; }
palPrimary->alWSGroupHandle = hWSGroup;
TRACE_OUT(("Opened AL workset group, handle 0x%x", hWSGroup));
//
// Open workset 0 in the workset group - this will be used to transfer
// 'load results' from site to site
//
OM_WorksetOpenPReq(palPrimary->pomClient, palPrimary->alWSGroupHandle, 0, NET_LOW_PRIORITY, FALSE, &palPrimary->omWSCorrelator);
DC_EXIT_POINT: DebugExitVOID(ALWorksetRegisterCon); }
//
// ALRemoteLoadResult()
//
BOOL ALRemoteLoadResult ( PAL_PRIMARY palPrimary, OM_WSGROUP_HANDLE alWSGroup, POM_OBJECT pObj ) { CM_STATUS cmStatus; BOOL fHandled = FALSE; POM_OBJECTDATA pData = NULL; TSHR_AL_LOAD_RESULT alLoadResult;
DebugEntry(ALRemoteLoadResult);
ValidateALP(palPrimary);
//
// Find the call information stored for this call
//
// If the workset group is not in out list of calls, then this event
// is for a group the Application Loader has registered with. The
// event should be passed onto other event procedures.
//
if (!palPrimary->inCall || (palPrimary->alWSGroupHandle != alWSGroup)) { TRACE_OUT(("WSG 0x%x not the AL WSG", alWSGroup)); DC_QUIT; }
//
// We care
//
fHandled = TRUE;
//
// Read the object
//
if (OM_ObjectRead(palPrimary->pomClient, alWSGroup, 0, pObj, &pData) != 0) { ERROR_OUT(( "Could not access object")); DC_QUIT; }
//
// Take a copy of the information so we can release the object straight
// away
//
memcpy(&alLoadResult, &pData->data, sizeof(alLoadResult));
//
// Release the object
//
OM_ObjectRelease(palPrimary->pomClient, alWSGroup, 0, pObj, &pData);
//
// Convert the machine name to a person handle for this machine
//
TRACE_OUT(("Load result for FP %s is %d for person %s", alLoadResult.szFunctionProfile, alLoadResult.result, alLoadResult.personName));
//
// If the load was successful, don't bother notifying WB; it isn't
// going to do anything.
//
if (alLoadResult.result == AL_LOAD_SUCCESS) { TRACE_OUT(("Load was successful; Whiteboard doesn't care")); DC_QUIT; }
//
// If this was us, also don't notify WB.
//
CMS_GetStatus(&cmStatus); if (!lstrcmp(alLoadResult.personName, cmStatus.localName)) { TRACE_OUT(("Load was for local dude; Whiteboard doesn't care")); DC_QUIT; }
//
// Map function profile to type
//
if (OMMapNameToFP(alLoadResult.szFunctionProfile) == OMFP_WB) { if (palPrimary->putWB != NULL) { UT_PostEvent(palPrimary->putTask, palPrimary->putWB, 0, ALS_REMOTE_LOAD_RESULT, alLoadResult.result, 0); } }
DC_EXIT_POINT: DebugExitBOOL(ALRemoteLoadResult, fHandled); return(fHandled); }
//
// ALStartStopWB()
//
// This takes care of starting/stopping the old Whiteboard applet. This is
// no longer a separate EXE. It is now a DLL (though still MFC) which gets
// loaded in CONF's process. We take care of LoadLibrary()ing it the first
// time it is pulled in, either via normal or auto launch. Then we call into
// it to get a new thread/window.
//
// By having CONF post a message to the primary task, where autolaunch also
// happens, we get the load synchronized. It is only ever done from the
// same thread, meaning we don't have to create extra protection for our
// variables.
//
// fNewWB is a TEMP HACK variable to launch the new whiteboard until we
// have the T.120 wiring in place
//
BOOL ALStartStopWB(PAL_PRIMARY palPrimary, LPCTSTR szFileNameCopy) { BOOL fSuccess;
DebugEntry(ALStartStopWB);
if (!palPrimary->putWB) { //
// Whiteboard isn't running, we can only start it.
//
// This won't return until WB is initialized and registered.
// We own the AL lock, so we don't have to worry about starting
// more than one thread at a time, etc.
//
DCS_StartThread(OldWBThreadProc); }
fSuccess = (palPrimary->putWB != NULL); if (fSuccess) { UT_PostEvent(palPrimary->putTask, palPrimary->putWB, 0, ALS_LOCAL_LOAD, 0, (UINT_PTR)szFileNameCopy); }
DebugExitBOOL(ALStartStopWB, fSuccess); return(fSuccess); }
//
// This is the whiteboard thread. We have the thread code actually in our
// DLL, so we can control when WB is running. The proc loads the WB dll,
// calls Run(), then frees the dll.
//
DWORD WINAPI OldWBThreadProc(LPVOID hEventWait) { DWORD rc = 0; HMODULE hLibWB; PFNINITWB pfnInitWB; PFNRUNWB pfnRunWB; PFNTERMWB pfnTermWB;
DebugEntry(OldWBThreadProc);
//
// Load the WB library
//
hLibWB = NmLoadLibrary(TEXT("nmoldwb.dll"),FALSE); if (!hLibWB) { ERROR_OUT(("Can't start 2.x whiteboard; nmoldwb.dll not loaded")); DC_QUIT; }
pfnInitWB = (PFNINITWB)GetProcAddress(hLibWB, "InitWB"); pfnRunWB = (PFNRUNWB)GetProcAddress(hLibWB, "RunWB"); pfnTermWB = (PFNTERMWB)GetProcAddress(hLibWB, "TermWB");
if (!pfnInitWB || !pfnRunWB || !pfnTermWB) { ERROR_OUT(("Can't start 2.x whiteboard; nmoldwb.dll is wrong version")); DC_QUIT; }
//
// Let WB do its thing. When it has inited, it will pulse the event,
// which will let the caller continue.
//
if (!pfnInitWB()) { ERROR_OUT(("Couldn't initialize whiteboard")); } else { //
// The AL/OM thread is blocked waiting for us to set the event.
// It owns the AL critsect. So we can modify the global variable
// without taking the critsect.
//
ASSERT(g_palPrimary != NULL);
// Bump up shared mem ref count
UT_BumpUpRefCount(g_palPrimary);
// Save WB task for event posting
ASSERT(g_autTasks[UTTASK_WB].dwThreadId); g_palPrimary->putWB = &g_autTasks[UTTASK_WB];
// Register exit cleanup proc
UT_RegisterExit(g_palPrimary->putWB, ALSExitProc, NULL);
//
// Let the caller continue. The run code is going to do message
// loop stuff.
//
SetEvent((HANDLE)hEventWait); pfnRunWB();
//
// This will cleanup if we haven't already
//
ALSExitProc(NULL); } pfnTermWB();
DC_EXIT_POINT:
if (hLibWB != NULL) { //
// Free the WB dll
//
FreeLibrary(hLibWB); }
return(0); }
//
// ALSExitProc()
//
void CALLBACK ALSExitProc(LPVOID data) { DebugEntry(ALSecExitProc);
UT_Lock(UTLOCK_AL);
ASSERT(g_palPrimary != NULL);
//
// Deregister exit procedure (if registered call UT_DeregisterExit()
// with ALSecExitProc()).
//
UT_DeregisterExit(g_palPrimary->putWB, ALSExitProc, NULL); g_palPrimary->putWB = NULL;
//
// Bump down ref count on AL primary
//
UT_FreeRefCount((void**)&g_palPrimary, TRUE);
UT_Unlock(UTLOCK_AL);
DebugExitVOID(ALSExitProc); }
|