857 lines
15 KiB
C++
857 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) 1994-95 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
appobj.cpp
|
|
|
|
Abstract:
|
|
|
|
OLE-createable application object implementation.
|
|
|
|
Author:
|
|
|
|
Don Ryan (donryan) 27-Dec-1994
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
Jeff Parham (jeffparh) 16-Jan-1996
|
|
Added Get/SetLastTargetServer() to help isolate server connection
|
|
problems. (Bug #2993.)
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "llsmgr.h"
|
|
#include "lmerr.h"
|
|
#include "lmcons.h"
|
|
#include "lmwksta.h"
|
|
#include "lmapibuf.h"
|
|
#include "lmserver.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
IMPLEMENT_DYNCREATE(CApplication, CCmdTarget)
|
|
// IMPLEMENT_OLECREATE(CApplication, "Llsmgr.Application.1", 0x2c5dffb3, 0x472f, 0x11ce, 0xa0, 0x30, 0x0, 0xaa, 0x0, 0x33, 0x9a, 0x98)
|
|
|
|
BEGIN_MESSAGE_MAP(CApplication, CCmdTarget)
|
|
//{{AFX_MSG_MAP(CApplication)
|
|
// NOTE - the ClassWizard will add and remove mapping macros here.
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
BEGIN_DISPATCH_MAP(CApplication, CCmdTarget)
|
|
//{{AFX_DISPATCH_MAP(CApplication)
|
|
DISP_PROPERTY_EX(CApplication, "Application", GetApplication, SetNotSupported, VT_DISPATCH)
|
|
DISP_PROPERTY_EX(CApplication, "FullName", GetFullName, SetNotSupported, VT_BSTR)
|
|
DISP_PROPERTY_EX(CApplication, "Name", GetName, SetNotSupported, VT_BSTR)
|
|
DISP_PROPERTY_EX(CApplication, "Parent", GetParent, SetNotSupported, VT_DISPATCH)
|
|
DISP_PROPERTY_EX(CApplication, "Visible", GetVisible, SetNotSupported, VT_BOOL)
|
|
DISP_PROPERTY_EX(CApplication, "ActiveController", GetActiveController, SetNotSupported, VT_DISPATCH)
|
|
DISP_PROPERTY_EX(CApplication, "ActiveDomain", GetActiveDomain, SetNotSupported, VT_DISPATCH)
|
|
DISP_PROPERTY_EX(CApplication, "LocalDomain", GetLocalDomain, SetNotSupported, VT_DISPATCH)
|
|
DISP_PROPERTY_EX(CApplication, "IsFocusDomain", IsFocusDomain, SetNotSupported, VT_BOOL)
|
|
DISP_PROPERTY_EX(CApplication, "LastErrorString", GetLastErrorString, SetNotSupported, VT_BSTR)
|
|
DISP_FUNCTION(CApplication, "Quit", Quit, VT_EMPTY, VTS_NONE)
|
|
DISP_FUNCTION(CApplication, "SelectDomain", SelectDomain, VT_BOOL, VTS_VARIANT)
|
|
DISP_FUNCTION(CApplication, "SelectEnterprise", SelectEnterprise, VT_BOOL, VTS_NONE)
|
|
DISP_PROPERTY_PARAM(CApplication, "Domains", GetDomains, SetNotSupported, VT_DISPATCH, VTS_VARIANT)
|
|
DISP_DEFVALUE(CApplication, "Name")
|
|
//}}AFX_DISPATCH_MAP
|
|
END_DISPATCH_MAP()
|
|
|
|
|
|
CApplication::CApplication()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for OLE-createable application object.
|
|
|
|
To keep the application running as long as an OLE automation
|
|
object is active, we must call AfxOleLockApp.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EnableAutomation();
|
|
|
|
ASSERT(theApp.m_pApplication == NULL);
|
|
|
|
if (theApp.m_pApplication == NULL)
|
|
theApp.m_pApplication = this;
|
|
|
|
if (theApp.m_bIsAutomated)
|
|
AfxOleLockApp();
|
|
|
|
m_pDomains = NULL;
|
|
m_pLocalDomain = NULL;
|
|
m_pActiveDomain = NULL;
|
|
m_bIsFocusDomain = FALSE;
|
|
m_bDomainsRefreshed = FALSE;
|
|
|
|
m_strLastTargetServer = TEXT("");
|
|
|
|
m_domainArray.RemoveAll();
|
|
|
|
m_pActiveController = new CController;
|
|
m_idStatus = m_pActiveController ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
}
|
|
|
|
|
|
CApplication::~CApplication()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for OLE-createable application object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(theApp.m_pApplication == this);
|
|
|
|
if (theApp.m_pApplication == this)
|
|
theApp.m_pApplication = NULL;
|
|
|
|
if (theApp.m_bIsAutomated)
|
|
AfxOleUnlockApp();
|
|
|
|
if (m_pDomains)
|
|
m_pDomains->InternalRelease();
|
|
|
|
if (m_pLocalDomain)
|
|
m_pLocalDomain->InternalRelease();
|
|
|
|
if (m_pActiveDomain)
|
|
m_pActiveDomain->InternalRelease();
|
|
|
|
if (m_pActiveController)
|
|
m_pActiveController->InternalRelease();
|
|
}
|
|
|
|
|
|
void CApplication::OnFinalRelease()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When the last reference for an automation object is released
|
|
OnFinalRelease is called. This implementation deletes object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ResetDomains();
|
|
delete this;
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetActiveController()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the active license controller object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH or VT_EMPTY.
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_VALID(m_pActiveController);
|
|
return m_pActiveController->GetIDispatch(TRUE);
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetActiveDomain()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the active domain object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH or VT_EMPTY.
|
|
|
|
--*/
|
|
|
|
{
|
|
return m_pActiveDomain ? m_pActiveDomain->GetIDispatch(TRUE) : NULL;
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetApplication()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the application object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH.
|
|
|
|
--*/
|
|
|
|
{
|
|
return GetIDispatch(TRUE);
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetDomains(const VARIANT FAR& index)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns a collection object containing all of the domains
|
|
visible to the local machine or returns an individual domain
|
|
described by an index into the collection.
|
|
|
|
Arguments:
|
|
|
|
index - optional argument that may be a string (VT_BSTR)
|
|
indicating a domain name or a number (VT_I4) indicating
|
|
the position within collection.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH or VT_EMPTY.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPDISPATCH lpdispatch = NULL;
|
|
|
|
if (!m_pDomains)
|
|
{
|
|
m_pDomains = new CDomains(this, &m_domainArray);
|
|
}
|
|
|
|
if (m_pDomains)
|
|
{
|
|
if (V_ISVOID((VARIANT FAR*)&index))
|
|
{
|
|
if (RefreshDomains())
|
|
{
|
|
lpdispatch = m_pDomains->GetIDispatch(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_bDomainsRefreshed)
|
|
{
|
|
lpdispatch = m_pDomains->GetItem(index);
|
|
}
|
|
else if (RefreshDomains())
|
|
{
|
|
lpdispatch = m_pDomains->GetItem(index);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastStatus(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
return lpdispatch;
|
|
}
|
|
|
|
|
|
BSTR CApplication::GetFullName()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the file specification for the application,
|
|
including path.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BSTR.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR szModuleFileName[260];
|
|
|
|
GetModuleFileName(AfxGetApp()->m_hInstance, szModuleFileName, 260);
|
|
return SysAllocStringLen(szModuleFileName, lstrlen(szModuleFileName));
|
|
}
|
|
|
|
|
|
BSTR CApplication::GetLastErrorString()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves string for last error.
|
|
|
|
(Routine stolen from winsadmn...).
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BSTR.
|
|
|
|
--*/
|
|
|
|
{
|
|
CString strLastError;
|
|
DWORD nId = m_idStatus;
|
|
|
|
if (((long)nId == RPC_S_CALL_FAILED) ||
|
|
((long)nId == RPC_NT_SS_CONTEXT_MISMATCH))
|
|
{
|
|
strLastError.LoadString(IDP_ERROR_DROPPED_LINK);
|
|
}
|
|
else if (((long)nId == RPC_S_SERVER_UNAVAILABLE) ||
|
|
((long)nId == RPC_NT_SERVER_UNAVAILABLE))
|
|
{
|
|
strLastError.LoadString(IDP_ERROR_NO_RPC_SERVER);
|
|
}
|
|
else if ((long)nId == STATUS_MEMBER_IN_GROUP)
|
|
{
|
|
strLastError.LoadString(IDP_ERROR_MEMBER_IN_GROUP);
|
|
}
|
|
else
|
|
{
|
|
HINSTANCE hinstDll = NULL;
|
|
|
|
if ((nId >= NERR_BASE) && (nId <= MAX_NERR))
|
|
{
|
|
hinstDll = ::LoadLibrary(_T("netmsg.dll"));
|
|
}
|
|
else if (nId >= 0x4000000)
|
|
{
|
|
hinstDll = ::LoadLibrary(_T("ntdll.dll"));
|
|
}
|
|
|
|
TCHAR szLastError[1024];
|
|
DWORD cchLastError = sizeof(szLastError) / sizeof(TCHAR);
|
|
|
|
DWORD dwFlags = FORMAT_MESSAGE_IGNORE_INSERTS|
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK|
|
|
(hinstDll ? FORMAT_MESSAGE_FROM_HMODULE
|
|
: FORMAT_MESSAGE_FROM_SYSTEM);
|
|
|
|
cchLastError = ::FormatMessage(
|
|
dwFlags,
|
|
hinstDll,
|
|
nId,
|
|
0,
|
|
szLastError,
|
|
cchLastError,
|
|
NULL
|
|
);
|
|
|
|
if (hinstDll)
|
|
{
|
|
::FreeLibrary(hinstDll);
|
|
}
|
|
|
|
if (cchLastError)
|
|
{
|
|
strLastError = szLastError;
|
|
}
|
|
else
|
|
{
|
|
strLastError.LoadString(IDP_ERROR_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
|
|
return strLastError.AllocSysString();
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetLocalDomain()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the local domain object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH or VT_EMPTY.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (!m_pLocalDomain)
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
PWKSTA_INFO_100 pWkstaInfo100 = NULL;
|
|
|
|
NetStatus = NetWkstaGetInfo(
|
|
NULL,
|
|
100,
|
|
(LPBYTE*)&pWkstaInfo100
|
|
);
|
|
|
|
if (NetStatus == ERROR_SUCCESS)
|
|
{
|
|
m_pLocalDomain = new CDomain(this, pWkstaInfo100->wki100_langroup);
|
|
|
|
if (!m_pLocalDomain)
|
|
{
|
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
NetApiBufferFree(pWkstaInfo100);
|
|
}
|
|
|
|
SetLastStatus(NetStatus); // called api
|
|
}
|
|
|
|
return m_pLocalDomain ? m_pLocalDomain->GetIDispatch(TRUE) : NULL;
|
|
}
|
|
|
|
|
|
BSTR CApplication::GetName()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the name of the application.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BSTR.
|
|
|
|
--*/
|
|
|
|
{
|
|
CString AppName = AfxGetAppName();
|
|
return AppName.AllocSysString();
|
|
}
|
|
|
|
|
|
LPDISPATCH CApplication::GetParent()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the parent of the object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_DISPATCH.
|
|
|
|
--*/
|
|
|
|
{
|
|
return GetApplication();
|
|
}
|
|
|
|
|
|
BOOL CApplication::GetVisible()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns whether or not the application is visible to the user.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BOOL.
|
|
|
|
--*/
|
|
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL CApplication::IsFocusDomain()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns true if application focused on domain.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BOOL.
|
|
|
|
--*/
|
|
|
|
{
|
|
return m_bIsFocusDomain;
|
|
}
|
|
|
|
|
|
BOOL CApplication::RefreshDomains()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Refreshs domain object list.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ResetDomains();
|
|
|
|
NET_API_STATUS NetStatus;
|
|
DWORD ResumeHandle = 0L;
|
|
|
|
int iDomain = 0;
|
|
|
|
do
|
|
{
|
|
DWORD EntriesRead;
|
|
DWORD TotalEntries;
|
|
LPBYTE ReturnBuffer = NULL;
|
|
|
|
NetStatus = NetServerEnum(
|
|
NULL, // servername
|
|
100, // level
|
|
&ReturnBuffer,
|
|
LLS_PREFERRED_LENGTH,
|
|
&EntriesRead,
|
|
&TotalEntries,
|
|
SV_TYPE_DOMAIN_ENUM,
|
|
NULL, // domain
|
|
&ResumeHandle
|
|
);
|
|
|
|
if (NetStatus == ERROR_SUCCESS ||
|
|
NetStatus == ERROR_MORE_DATA)
|
|
{
|
|
CDomain* pDomain;
|
|
PSERVER_INFO_100 pServerInfo100;
|
|
|
|
pServerInfo100 = (PSERVER_INFO_100)ReturnBuffer;
|
|
|
|
ASSERT(iDomain == m_domainArray.GetSize());
|
|
m_domainArray.SetSize(m_domainArray.GetSize() + EntriesRead);
|
|
|
|
while (EntriesRead--)
|
|
{
|
|
pDomain = new CDomain(this, pServerInfo100->sv100_name);
|
|
|
|
m_domainArray.SetAt(iDomain++, pDomain); // validate later
|
|
pServerInfo100++;
|
|
}
|
|
|
|
NetApiBufferFree(ReturnBuffer);
|
|
}
|
|
|
|
} while (NetStatus == ERROR_MORE_DATA);
|
|
|
|
SetLastStatus(NetStatus); // called api
|
|
|
|
if (NetStatus == ERROR_SUCCESS)
|
|
{
|
|
m_bDomainsRefreshed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ResetDomains();
|
|
}
|
|
|
|
return m_bDomainsRefreshed;
|
|
}
|
|
|
|
|
|
void CApplication::ResetDomains()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets domain object list.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CDomain* pDomain;
|
|
INT_PTR iDomain = m_domainArray.GetSize();
|
|
|
|
while (iDomain--)
|
|
{
|
|
if (pDomain = (CDomain*)m_domainArray[iDomain])
|
|
{
|
|
ASSERT(pDomain->IsKindOf(RUNTIME_CLASS(CDomain)));
|
|
pDomain->InternalRelease();
|
|
}
|
|
}
|
|
|
|
m_domainArray.RemoveAll();
|
|
m_bDomainsRefreshed = FALSE;
|
|
}
|
|
|
|
|
|
BOOL CApplication::SelectDomain(const VARIANT FAR& domain)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connects to license controller of specified domain.
|
|
|
|
Arguments:
|
|
|
|
domain - name of domain.
|
|
|
|
Return Values:
|
|
|
|
VT_BOOL.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bIsSelected = FALSE;
|
|
|
|
ASSERT_VALID(m_pActiveController);
|
|
|
|
if (bIsSelected = m_pActiveController->Connect(domain))
|
|
{
|
|
LPTSTR pszActiveDomain = MKSTR(m_pActiveController->m_strActiveDomainName);
|
|
|
|
if (m_pActiveDomain)
|
|
{
|
|
m_pActiveDomain->InternalRelease();
|
|
m_pActiveDomain = NULL;
|
|
}
|
|
|
|
if (pszActiveDomain && *pszActiveDomain)
|
|
{
|
|
m_pActiveDomain = new CDomain(this, pszActiveDomain);
|
|
|
|
if (m_pActiveDomain)
|
|
{
|
|
m_bIsFocusDomain = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_bIsFocusDomain = FALSE; // invalidate m_pActiveDomain
|
|
SetLastStatus(STATUS_NO_MEMORY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bIsFocusDomain = FALSE; // invalidate m_pActiveDomain
|
|
}
|
|
}
|
|
|
|
return bIsSelected;
|
|
}
|
|
|
|
|
|
BOOL CApplication::SelectEnterprise()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connects to license controller of enterprise.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BOOL.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bIsSelected = FALSE;
|
|
|
|
VARIANT va;
|
|
VariantInit(&va); // connect to default controller
|
|
|
|
if (bIsSelected = m_pActiveController->Connect(va))
|
|
{
|
|
if (m_pActiveDomain)
|
|
{
|
|
m_pActiveDomain->InternalRelease();
|
|
m_pActiveDomain = NULL;
|
|
}
|
|
|
|
m_bIsFocusDomain = FALSE;
|
|
}
|
|
|
|
return bIsSelected;
|
|
}
|
|
|
|
|
|
void CApplication::Quit()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes all documents and exits the application.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
AfxPostQuitMessage(0); // no main window...
|
|
}
|
|
|
|
|
|
BSTR CApplication::GetLastTargetServer()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves string for last server to which we tried to connect.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Values:
|
|
|
|
VT_BSTR.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( m_strLastTargetServer.IsEmpty() )
|
|
return NULL;
|
|
else
|
|
return m_strLastTargetServer.AllocSysString();
|
|
}
|
|
|
|
|
|
void CApplication::SetLastTargetServer( LPCTSTR pszServerName )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets string for last server to which we tried to connect.
|
|
|
|
Arguments:
|
|
|
|
pszServerName - last server name to which we tried to connect.
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
m_strLastTargetServer = pszServerName;
|
|
}
|