337 lines
8.8 KiB
C++
337 lines
8.8 KiB
C++
|
//
|
||
|
// User or remote site invokes applet
|
||
|
//
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include "appldr.h"
|
||
|
#include "cuserdta.hpp"
|
||
|
#include "csap.h"
|
||
|
|
||
|
#define count_of(array) (sizeof(array) / sizeof(array[0]))
|
||
|
|
||
|
|
||
|
static CRITICAL_SECTION g_csAppLdrInfo;
|
||
|
static AppLoaderInfo g_aAppLoaderInfo[APPLET_LAST];
|
||
|
static BOOL g_fAppLdrInitialized = FALSE;
|
||
|
|
||
|
const static CHAR *g_fnAppletDLL[APPLET_LAST] = {"nmwb.dll", "nmft.dll", "nmchat.dll"};
|
||
|
|
||
|
// Chat session key
|
||
|
static const GUID guidNM2Chat = { 0x340f3a60, 0x7067, 0x11d0,
|
||
|
{ 0xa0, 0x41, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
|
||
|
#define CHAT_KEY_SIZE 25
|
||
|
extern struct Key CHAT_APP_PROTO_KEY;
|
||
|
|
||
|
|
||
|
// NetMeeting/UI, T.120
|
||
|
T120Error WINAPI T120_LoadApplet
|
||
|
(
|
||
|
APPLET_ID nAppId,
|
||
|
BOOL flocal,
|
||
|
T120ConfID nConfId,
|
||
|
BOOL fNoUI,
|
||
|
LPSTR pszCmdLine
|
||
|
)
|
||
|
{
|
||
|
T120Error rc = T120_NO_ERROR;
|
||
|
LPFN_CREATE_APPLET_LOADER_INTERFACE pfnCreateInterface;
|
||
|
|
||
|
if (nAppId >= APPLET_LAST)
|
||
|
{
|
||
|
ERROR_OUT(("T120_LoadApplet: invalid applet ID=%u", nAppId));
|
||
|
return T120_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check policies. Launch & auto-launch not allowed if corp has
|
||
|
// disabled applet.
|
||
|
//
|
||
|
RegEntry rePol(POLICIES_KEY, HKEY_CURRENT_USER);
|
||
|
switch (nAppId)
|
||
|
{
|
||
|
case APPLET_ID_WB:
|
||
|
if (rePol.GetNumber(REGVAL_POL_NO_NEWWHITEBOARD, DEFAULT_POL_NO_NEWWHITEBOARD))
|
||
|
{
|
||
|
WARNING_OUT(("New WB disabled by policy, not starting"));
|
||
|
return GCC_NO_SUCH_APPLICATION;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case APPLET_ID_FT:
|
||
|
if (rePol.GetNumber(REGVAL_POL_NO_FILETRANSFER_SEND, DEFAULT_POL_NO_FILETRANSFER_SEND) &&
|
||
|
rePol.GetNumber(REGVAL_POL_NO_FILETRANSFER_RECEIVE, DEFAULT_POL_NO_FILETRANSFER_RECEIVE))
|
||
|
{
|
||
|
WARNING_OUT(("FT disabled by policy, not starting"));
|
||
|
return GCC_NO_SUCH_APPLICATION;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case APPLET_ID_CHAT:
|
||
|
if (rePol.GetNumber(REGVAL_POL_NO_CHAT, DEFAULT_POL_NO_CHAT))
|
||
|
{
|
||
|
WARNING_OUT(("Chat disabled by policy, not starting"));
|
||
|
return GCC_NO_SUCH_APPLICATION;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
::EnterCriticalSection(&g_csAppLdrInfo);
|
||
|
|
||
|
if (NULL != g_aAppLoaderInfo[nAppId].hLibApplet)
|
||
|
{
|
||
|
switch (g_aAppLoaderInfo[nAppId].eStatus)
|
||
|
{
|
||
|
case APPLET_CLOSING:
|
||
|
case APPLET_WORK_THREAD_EXITED:
|
||
|
WARNING_OUT(("T120_LoadApplet: applet is closing or work thread exited"));
|
||
|
rc = GCC_APPLET_EXITING;
|
||
|
break;
|
||
|
default:
|
||
|
if (APPLDR_NO_ERROR == g_aAppLoaderInfo[nAppId].pIAppLoader->AppletInvoke(flocal, nConfId, pszCmdLine))
|
||
|
{
|
||
|
g_aAppLoaderInfo[nAppId].cLoads++;
|
||
|
}
|
||
|
// rc = T120_NO_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
goto MyExit;
|
||
|
}
|
||
|
|
||
|
g_aAppLoaderInfo[nAppId].hLibApplet = ::LoadLibrary(g_fnAppletDLL[nAppId]);
|
||
|
if (NULL != g_aAppLoaderInfo[nAppId].hLibApplet)
|
||
|
{
|
||
|
pfnCreateInterface = (LPFN_CREATE_APPLET_LOADER_INTERFACE)
|
||
|
::GetProcAddress(g_aAppLoaderInfo[nAppId].hLibApplet,
|
||
|
CREATE_APPLET_LOADER_INTERFACE);
|
||
|
if (NULL != pfnCreateInterface)
|
||
|
{
|
||
|
//g_aAppLoaderInfo[nAppId].pIAppLoader = (IAppletLoader*)(*pfnCreateInterface)();
|
||
|
(*pfnCreateInterface)(&g_aAppLoaderInfo[nAppId].pIAppLoader);
|
||
|
if (NULL != g_aAppLoaderInfo[nAppId].pIAppLoader)
|
||
|
{
|
||
|
if (APPLDR_NO_ERROR == g_aAppLoaderInfo[nAppId].pIAppLoader->AppletStartup(fNoUI))
|
||
|
{
|
||
|
if (APPLDR_NO_ERROR == g_aAppLoaderInfo[nAppId].pIAppLoader->AppletInvoke(flocal, nConfId, pszCmdLine))
|
||
|
{
|
||
|
g_aAppLoaderInfo[nAppId].cLoads++;
|
||
|
// rc = T120_NO_ERROR;
|
||
|
goto MyExit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_LoadApplet: cannot invoke applet(%s), flocal=%u, nConfID=%u",
|
||
|
g_fnAppletDLL[nAppId], flocal, nConfId));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_LoadApplet: cannot start applet(%s)", g_fnAppletDLL[nAppId]));
|
||
|
}
|
||
|
|
||
|
g_aAppLoaderInfo[nAppId].pIAppLoader->ReleaseInterface();
|
||
|
g_aAppLoaderInfo[nAppId].pIAppLoader = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_LoadApplet: Entry function of %s failed.\n", g_fnAppletDLL[nAppId]));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WARNING_OUT(("T120_LoadApplet: Can't find entry point of %s.\n", g_fnAppletDLL[nAppId]));
|
||
|
}
|
||
|
|
||
|
::FreeLibrary(g_aAppLoaderInfo[nAppId].hLibApplet);
|
||
|
g_aAppLoaderInfo[nAppId].hLibApplet = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_LoadApplet: Can't open DLL %s, err %d.\n", g_fnAppletDLL[nAppId], GetLastError()));
|
||
|
}
|
||
|
|
||
|
rc = GCC_NO_SUCH_APPLICATION;
|
||
|
|
||
|
MyExit:
|
||
|
|
||
|
::LeaveCriticalSection(&g_csAppLdrInfo);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
|
||
|
// NetMeeting/UI shutdown
|
||
|
T120Error WINAPI
|
||
|
T120_CloseApplet(APPLET_ID nAppId, BOOL fNowRegardlessRefCount, BOOL fSync, DWORD dwTimeout)
|
||
|
{
|
||
|
if (nAppId< APPLET_LAST)
|
||
|
{
|
||
|
if (g_fAppLdrInitialized)
|
||
|
{
|
||
|
::EnterCriticalSection(&g_csAppLdrInfo);
|
||
|
IAppletLoader *pIAppLdr = g_aAppLoaderInfo[nAppId].pIAppLoader;
|
||
|
if (NULL != pIAppLdr)
|
||
|
{
|
||
|
ASSERT(g_aAppLoaderInfo[nAppId].cLoads > 0);
|
||
|
g_aAppLoaderInfo[nAppId].cLoads --;
|
||
|
if ((! fNowRegardlessRefCount) && g_aAppLoaderInfo[nAppId].cLoads > 0)
|
||
|
{
|
||
|
pIAppLdr = NULL; // do not free the library
|
||
|
}
|
||
|
}
|
||
|
::LeaveCriticalSection(&g_csAppLdrInfo);
|
||
|
|
||
|
if (NULL != pIAppLdr)
|
||
|
{
|
||
|
// AppletCleanup() must be outside of the critical section
|
||
|
// because applet worker thread will call AppletStatus() before
|
||
|
// exiting its worker thread.
|
||
|
switch (pIAppLdr->AppletCleanup(5000)) // always synchronous shutdown
|
||
|
{
|
||
|
case APPLDR_NO_ERROR :
|
||
|
// we are closing this applet
|
||
|
g_aAppLoaderInfo[nAppId].eStatus = APPLET_CLOSING;
|
||
|
|
||
|
// it is safe to unload the library
|
||
|
::FreeLibrary(g_aAppLoaderInfo[nAppId].hLibApplet);
|
||
|
g_aAppLoaderInfo[nAppId].hLibApplet = NULL;
|
||
|
break;
|
||
|
|
||
|
case APPLDR_CANCEL_EXIT:
|
||
|
//
|
||
|
// The app didn't want to be unloaded
|
||
|
//
|
||
|
::EnterCriticalSection(&g_csAppLdrInfo);
|
||
|
g_aAppLoaderInfo[nAppId].cLoads++;
|
||
|
g_aAppLoaderInfo[nAppId].pIAppLoader = pIAppLdr;
|
||
|
::LeaveCriticalSection(&g_csAppLdrInfo);
|
||
|
return GCC_APPLET_CANCEL_EXIT;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return T120_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_CloseApplet: invalid applet ID=%u", nAppId));
|
||
|
}
|
||
|
return T120_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
T120Error WINAPI
|
||
|
T120_QueryApplet(APPLET_ID nAppId, APPLET_QUERY_ID eQueryId)
|
||
|
{
|
||
|
if (nAppId< APPLET_LAST)
|
||
|
{
|
||
|
if (g_fAppLdrInitialized)
|
||
|
{
|
||
|
::EnterCriticalSection(&g_csAppLdrInfo);
|
||
|
IAppletLoader *pIAppLdr = g_aAppLoaderInfo[nAppId].pIAppLoader;
|
||
|
::LeaveCriticalSection(&g_csAppLdrInfo);
|
||
|
if (NULL != pIAppLdr)
|
||
|
{
|
||
|
if (APPLET_QUERY_NM2xNODE == eQueryId)
|
||
|
{
|
||
|
pIAppLdr->OnNM2xNodeJoin();
|
||
|
}
|
||
|
else if (APPLDR_CANCEL_EXIT == pIAppLdr->AppletQuery(eQueryId))
|
||
|
{
|
||
|
return GCC_APPLET_CANCEL_EXIT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return T120_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_CloseApplet: invalid applet ID=%u", nAppId));
|
||
|
}
|
||
|
return T120_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Applet itself
|
||
|
T120Error WINAPI
|
||
|
T120_AppletStatus(APPLET_ID nAppId, APPLET_STATUS status)
|
||
|
{
|
||
|
if (nAppId < APPLET_LAST)
|
||
|
{
|
||
|
if (g_fAppLdrInitialized)
|
||
|
{
|
||
|
::EnterCriticalSection(&g_csAppLdrInfo);
|
||
|
|
||
|
g_aAppLoaderInfo[nAppId].eStatus = status;
|
||
|
|
||
|
switch (status)
|
||
|
{
|
||
|
case APPLET_WORK_THREAD_EXITED:
|
||
|
if (NULL != g_aAppLoaderInfo[nAppId].pIAppLoader)
|
||
|
{
|
||
|
g_aAppLoaderInfo[nAppId].pIAppLoader->ReleaseInterface();
|
||
|
g_aAppLoaderInfo[nAppId].pIAppLoader = NULL;
|
||
|
}
|
||
|
break;
|
||
|
case APPLET_LIBRARY_FREED:
|
||
|
// clean up this entry
|
||
|
::ZeroMemory(&g_aAppLoaderInfo[nAppId], sizeof(g_aAppLoaderInfo[0]));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
::LeaveCriticalSection(&g_csAppLdrInfo);
|
||
|
}
|
||
|
return T120_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_OUT(("T120_AppletStatus: invalid applet ID=%u", nAppId));
|
||
|
}
|
||
|
return T120_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
T120Error AppLdr_Initialize(void)
|
||
|
{
|
||
|
ASSERT(count_of(g_aAppLoaderInfo) == APPLET_LAST);
|
||
|
|
||
|
::InitializeCriticalSection(&g_csAppLdrInfo);
|
||
|
|
||
|
// clean all entries
|
||
|
::ZeroMemory(g_aAppLoaderInfo, sizeof(g_aAppLoaderInfo));
|
||
|
|
||
|
::CreateH221AppKeyFromGuid(CHAT_APP_PROTO_KEY.u.h221_non_standard.value,
|
||
|
(GUID *)&guidNM2Chat );
|
||
|
CHAT_APP_PROTO_KEY.choice = h221_non_standard_chosen;
|
||
|
CHAT_APP_PROTO_KEY.u.h221_non_standard.length = CHAT_KEY_SIZE;
|
||
|
|
||
|
g_fAppLdrInitialized = TRUE;
|
||
|
return T120_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AppLdr_Shutdown(void)
|
||
|
{
|
||
|
g_fAppLdrInitialized = FALSE;
|
||
|
|
||
|
for (ULONG i = 0; i < APPLET_LAST; i++)
|
||
|
{
|
||
|
if (NULL != g_aAppLoaderInfo[i].pIAppLoader)
|
||
|
{
|
||
|
APPLDR_RESULT rc = g_aAppLoaderInfo[i].pIAppLoader->AppletCleanup(5000); // always synchronous shutdown
|
||
|
ASSERT(APPLDR_NO_ERROR == rc);
|
||
|
|
||
|
// it is safe to unload the library
|
||
|
::FreeLibrary(g_aAppLoaderInfo[i].hLibApplet);
|
||
|
g_aAppLoaderInfo[i].hLibApplet = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// clean all entries
|
||
|
::ZeroMemory(g_aAppLoaderInfo, sizeof(g_aAppLoaderInfo));
|
||
|
|
||
|
::DeleteCriticalSection(&g_csAppLdrInfo);
|
||
|
}
|
||
|
|
||
|
|