1167 lines
29 KiB
C++
1167 lines
29 KiB
C++
#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 = LoadLibrary(TEXT("nmoldwb.dll"));
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|