コード例 #1
0
/////////////////////////////////////////////////////////////////////////////
// CBinder::GetObjectDesc
//
/////////////////////////////////////////////////////////////////////////////
WCHAR* CBinder::GetObjectDesc()
{
	if(!m_strObjectDesc && m_guidSource != GUID_NULL)
	{
		if(m_guidSource == CLSID_RootBinder)
			m_strObjectDesc.CopyFrom(L"Root Binder");
		else
			m_strObjectDesc.CopyFrom(GetProgID(m_guidSource));
	}

	return m_strObjectDesc;
}
コード例 #2
0
ファイル: server.cpp プロジェクト: y921111/VB_OPCClient_Code
// **************************************************************************
// ShutdownRequest ()
//
// Description:
//	2.0 OPC servers provide a notification if they are shutting down while 
//	we are still connected.  The notification comes through our IKShutdownSink
//  and is passed on to the server object through this function.
//
// Parameters:
//  LPCTSTR		lpszReason		String sent from OPC server describing reason
//								  for shutdown.  Could be NULL string.
//
// Returns:
//  void
// **************************************************************************
void CKServer::ShutdownRequest (LPCTSTR lpszReason)
	{
	// Log "server requested shutdown" message:
	if (lpszReason)
		LogMsg (IDS_SERVER_REQUESTED_SHUTDOWN, GetProgID (), lpszReason);

	// Notify the document that an object has been shutdown (i.e., invalidated):

	// First get a pointer to the application's main window:
	CKMainWnd *pWnd = (CKMainWnd *) AfxGetMainWnd ();

	// Post the user defined "UM_SERVER_SHUTDOWN" message to the main window.
	// It will pass the message along to the docoument object.  It will expect
	// a pointer to this server object passed a the lParam.
	if (pWnd)
		pWnd->PostMessage (UM_SERVER_SHUTDOWN, 0, (LPARAM) this);
	}
コード例 #3
0
/////////////////////////////////////////////////////////////////
// HRESULT CError::GetGUID
//
/////////////////////////////////////////////////////////////////
HRESULT CError::GetGUID(GUID* pGuid)
{
	HRESULT	hr = S_OK;
	WCHAR* pwszProgID = NULL;

	if(m_pIErrorInfo)
	{
		//IErrorInfo::GetGUID
		XTEST(hr = m_pIErrorInfo->GetGUID(pGuid));
		
		if(pGuid)
			pwszProgID = GetProgID(*pGuid);
		TRACE_METHOD(hr, L"IErrorInfo::GetGuid(&\"%s\")", pwszProgID);
	}

	SAFE_FREE(pwszProgID);
	return hr;
}
コード例 #4
0
////////////////////////////////////////////////////////////////
// CStream::Stat
//
/////////////////////////////////////////////////////////////////
HRESULT CStream::Stat(STATSTG* pstatstg)
{
	ASSERT(pstatstg);
	HRESULT hr = S_OK;
	WCHAR* pwszProgID = NULL;

	if(m_pIStream)
	{	
		memset(pstatstg, 0, sizeof(STATSTG));

		//IStream::Stat
		XTEST(hr = m_pIStream->Stat(pstatstg, STATFLAG_DEFAULT));

		pwszProgID = GetProgID(pstatstg->clsid);
		TESTC(TRACE_METHOD(hr, L"IStream::Stat(&{\"%s\", %d, %ld, 0x%08x, 0x%08x, 0x%08x, %d, %d, \"%s\", 0x%08x, %d}, \"%s\")", pstatstg->pwcsName, pstatstg->type, (ULONG)pstatstg->cbSize.QuadPart, &pstatstg->mtime, &pstatstg->ctime, &pstatstg->atime, pstatstg->grfMode, pstatstg->grfLocksSupported, pwszProgID, pstatstg->grfStateBits, pstatstg->reserved, L"STATFLAG_DEFAULT"));
	}

CLEANUP:
	SAFE_FREE(pwszProgID);
	return hr;
}
コード例 #5
0
////////////////////////////////////////////////////////////////
// CDataSource::GetClassID
//
/////////////////////////////////////////////////////////////////
HRESULT CDataSource::GetClassID(CLSID* pclsid, WCHAR** ppwszProgID)
{
	HRESULT hr = S_OK;
	WCHAR* pwszProgID = NULL;

	if(!m_pIPersist)
		return E_FAIL;

	//IPersist::GetClassID
	XTEST(hr = m_pIPersist->GetClassID(pclsid));

	//Obtain ProgID
	if(pclsid)
		pwszProgID = GetProgID(*pclsid);
	TESTC(TRACE_METHOD(hr, L"IPersist::GetClassID(%s)", pwszProgID));
	
CLEANUP:
	if(ppwszProgID)
		*ppwszProgID = pwszProgID;
	else
		SAFE_FREE(pwszProgID);
	return hr;
}
コード例 #6
0
ファイル: server.cpp プロジェクト: y921111/VB_OPCClient_Code
// **************************************************************************
// RemoveGroup ()
//
// Description:
//	Remove an OPC Group from OPC server, and delete associated CKGroup object
//	if asked.
//
// Parameters:
//  CKGroup		*pGroup			Pointer to CKGroup associated with OPC Group
//								  to remove.
//	bool		bDelete			Delete CKGroup object after removing
//								  associated OPC Group. true by default.
//
// Returns:
//  void
// **************************************************************************
void CKServer::RemoveGroup (CKGroup *pGroup, bool bDelete /* = true */)
	{
	ASSERT (pGroup != NULL);

	HRESULT hr;

	// Uninitialize group with OPC server.  This means all interfaces it
	// is using are released.  It is good practice to do this BEFORE
	// issuing a remove group request.  Pass the bDelete value so the 
	// group knows to delete its items if any.
	pGroup->Uninitialize (bDelete);

	// remove the group from the OPC server
	if (pGroup->IsValid ())
		{
		ASSERT (m_pIServer != NULL);

		// Issue remove OPC Group request using IOPCServer interface.  Pointer to 
		// the IOPCServer interface, m_pIServer, should have been set in Connect().
		hr = m_pIServer->RemoveGroup (
			pGroup->GetServerHandle (),		// server handle for this group.
			pGroup->IsForceDeletion ());	// force a delete if this client has not released the group properly.

		// Log success or failure:
		if (SUCCEEDED (hr))
			LogMsg (IDS_GROUP_REMOVE_SUCCESS, pGroup->GetName (), GetProgID ());
		else
			LogMsg (IDS_GROUP_REMOVE_FAILURE, pGroup->GetName (), GetProgID (), hr);
		}

	// Delete the group if asked:
	if (bDelete)
		{
		// We need to remove the group from the linked list before we delete it.

		// To remove a link, we must first get pointers to the adjacent links:
		CKGroup *pPrev = pGroup->GetPrev ();
		CKGroup *pNext = pGroup->GetNext ();
		
		// If there is a "previous" link, then its "next" is removed link's "next",
		if (pPrev)
			pPrev->SetNext (pNext);

		// and if there is a "next" link, then its "previous" is removed link's "previous",
		if (pNext)
			pNext->SetPrev (pPrev);

		// and if removed link was the "head", then the new head is removed link's "next".
		if (pGroup == m_pGroupHead)
			m_pGroupHead = pNext;

		// Decrement the group count:
		--m_cdwGroups;

		// Delete the group object:
		delete pGroup;
		}
	else
		{
		// Since CKGroup object was not deleted, it should be flagged as invalid
		// becuase it no longer has an associated OPC Group in OPC Server.
		pGroup->SetValid (false);
		}
	}
コード例 #7
0
ファイル: server.cpp プロジェクト: y921111/VB_OPCClient_Code
// **************************************************************************
// AddGroup ()
//
// Description:
//	Called to add an OPC Group.  A CKGroup will be added to this object if
//	needed and a request to add a corresponding OPC Group to the OPC Server
//	will be made.
//
// Parameters:
//  CKGroup		*pGroup			Pointer to group object to add.
//	bool		bLoadingProject	Set to true if call is made during project 
//								  load so group can be added to this object's
//								  group list.  Otherwise we will assume group
//								  already exists in list, and only needs to
//								  added to OPC Server.
//
// Returns:
//  void
// **************************************************************************
void CKServer::AddGroup (CKGroup *pGroup, bool bLoadingProject /*= false */)
	{
	ASSERT (pGroup != NULL);

	// If the group is new add it to our list:
	if (!bLoadingProject)
		{
		// New groups are added to the head of the linked list.

		// That means new the groups's "next" group is old head of list,
		pGroup->SetNext (m_pGroupHead);

		// and the new group is the old head of list's "previous" group,
		if (m_pGroupHead)	
			m_pGroupHead->SetPrev (pGroup);
			
		// and that new group is now the new "head" of list.
		m_pGroupHead = pGroup;

		// Don't forget to bump up the group count:
		++m_cdwGroups;
		}

	// If we are connected to OPC Server, issue a request to add this group:
	if (m_bConnected)
		{
		// Initialize arguments for add group request:
		HRESULT hr				= E_FAIL;
		WCHAR *pszName			= NULL;
		long lBias				= pGroup->GetBias ();
		float fDeadband			= pGroup->GetDeadband ();
		LPCTSTR lpszName		= pGroup->GetName ();
		DWORD dwRevUpdateRate	= 0;
		OPCHANDLE hServer		= NULL;
		IUnknown *pUnknown		= NULL;

		// All strings transmitted by COM must be in wide character (Unicode) format.
		// Declare a buffer to contain name string in wide character format.
		WCHAR wchBuffer	[DEFBUFFSIZE];

		// Convert the string format:
		if (lpszName != NULL)
			{
#ifdef _UNICODE
			// String is already in Unicode format, so simply copy into buffer:
			lstrcpyn (wchBuffer, lpszName, sizeof (wchBuffer) / sizeof (WCHAR));
#else
			// String is not in Unicode format, so convert and place result into buffer:
			if (!MultiByteToWideChar (CP_ACP, 0, lpszName, -1, wchBuffer, DEFBUFFSIZE))
				{
				ASSERT (FALSE);
				return;
				}
#endif

			// Reassign name pointer to buffer:
			pszName = wchBuffer;
			}
		
		// Issue add OPC Group request using IOPCServer interface.  Pointer to 
		// the IOPCServer interface, m_pIServer, should have been set in Connect().
		hr = m_pIServer->AddGroup (
			pszName,					// [in] group name
			pGroup->IsActive (),		// [in] active state
			pGroup->GetUpdateRate (),	// [in] requested update rate
			(OPCHANDLE) pGroup,			// [in] our handle to this group
			&lBias,						// [in] time bias
			&fDeadband,					// [in] percent deadband
			pGroup->GetLanguageID (),	// [in] requested language ID
			&hServer,					// [out] server handle to this group
			&dwRevUpdateRate,			// [out] revised update rate
			IID_IUnknown,				// [in] request an IUknown pointer
			&pUnknown);

		// OPC Group was successfully added:
		if (SUCCEEDED (hr))
			{
			// Log success:
			LogMsg (IDS_GROUP_ADD_SUCCESS, pGroup->GetName (), GetProgID ());

			// Since OPC Group was successfully added, we can go ahead an initialize
			// the associated CKGroup object.

			// We can now consider group valid:
			pGroup->SetValid (TRUE);

			// We should have gotten a valid pointer to the OPC Groups's IUnknown interface.
			// Set some things that only make sence if we have a vaild IUnknown pointer:
			if (pUnknown)
				{
				// Set the OPC Server's handle for this group:
				pGroup->SetServerHandle (hServer);

				// Reset update rate if OPC Server does not support requested rate:
				if (pGroup->GetUpdateRate () != dwRevUpdateRate)
					pGroup->SetUpdateRate (dwRevUpdateRate);

				// Initialize the CKGroup object, which will include getting necessary
				// interface pointers from IUnknown:
				pGroup->Initialize (pUnknown);

				// We can release the IUnknown pointer since initialized group
				// should have gotten the interface pointers it needs from it.
				pUnknown->Release ();
				}
			else
				{
				TRACE (_T("OTC: Warning added group %s to OPC server, but IUnknown is invalid.\r\n"),
					pGroup->GetName ());
				}
			}

		// OPC Group was not successfully added:
		else
			{
			// Log message that says add OPC Group request failed:
			LogMsg (IDS_GROUP_ADD_FAILURE, pGroup->GetName (), GetProgID (), hr);
			}
		}

	// No connection:
	else
		{
		// Log message that says we can't add the OPC Group because we are not
		// connected to OPC Server:
		LogMsg (IDS_SERVER_ADD_GROUP_FAILED_NOCONNECTION, pGroup->GetName (), GetProgID ());
		}
	}
コード例 #8
0
ファイル: server.cpp プロジェクト: y921111/VB_OPCClient_Code
// **************************************************************************
// Disconnect ()
//
// Description:
//	Called to disconnect from OPC server.
//
// Parameters:
//  none
//
// Returns:
//  void
// **************************************************************************
void CKServer::Disconnect ()
	{
	// Log success if we were truly connected:
	if (m_bConnected == true)
		LogMsg (IDS_SERVER_DISCONNECTED, GetProgID ());

	// Reset member variable:
	m_bConnected = false;

	// Release all of our server interface references:
	if (m_pIServer)
		{
		m_pIServer->Release ();
		m_pIServer = NULL;
		}

	if (m_pICommon)
		{
		m_pICommon->Release ();
		m_pICommon = NULL;
		}

	if (m_pIConnPtContainer)
		{
		// Unadvise shutdown notifications:
		if (m_dwCookieShutdownSink != 0)
			{
			HRESULT hr = E_FAIL;
			IConnectionPoint *pCP = NULL;

			hr = m_pIConnPtContainer->FindConnectionPoint (IID_IOPCShutdown, &pCP);

			if (SUCCEEDED (hr))
				{
				hr = pCP->Unadvise (m_dwCookieShutdownSink);
				pCP->Release ();
				}

			if (FAILED (hr))
				{
				TRACE (_T("OTC: CKServer::Disconnect () - failed to unadvise shutdown notifications\r\n"));
				}

			m_dwCookieShutdownSink = 0;
			}

		if (m_pIShutdownSink != NULL)
			{
			m_pIShutdownSink->Release ();
			m_pIShutdownSink = NULL;
			}

		m_pIConnPtContainer->Release ();
		m_pIConnPtContainer = NULL;
		}

	if (m_pIItemProps)
		{
		m_pIItemProps->Release ();
		m_pIItemProps = NULL;
		}

	if (m_pIBrowse)
		{
		m_pIBrowse->Release ();
		m_pIBrowse = NULL;
		}

	if (m_pIPublicGroups)
		{
		m_pIPublicGroups->Release ();
		m_pIPublicGroups = NULL;
		}

	if (m_pIPersistFile)
		{
		m_pIPersistFile->Release ();
		m_pIPersistFile = NULL;
		}
	}
コード例 #9
0
ファイル: server.cpp プロジェクト: y921111/VB_OPCClient_Code
// **************************************************************************
// Connect ()
//
// Description:
//	Connect to OPC Server.  OPC Server's ProgID and machine	name must have
//  been previously specified.
//
// Parameters:
//  none
//
// Returns:
//  bool - true if success.
// **************************************************************************
bool CKServer::Connect ()
	{
	// Program ID of OPC Server should have been defined by now:
	ASSERT (!m_strProgID.IsEmpty ());

	// Assume we are not connecting to KEPServerEx:
	m_bfFlags.bIsKepServerEx = false;

	// Perform any necessary cleanup from a previous connection:
	Disconnect ();

/*
m_server.EnumClassesOfCategories( 
1, 
&catids 
0, 
NULL, 
out enumerator);
*/


	// Obtain the Class ID of the OPC Server.  (GetCLSID() will need the
	// OPC Server's Program ID to succeed.  That's why we checked it above.)
	CLSID clsid;
	bool ret = SUCCEEDED (GetCLSID (clsid));

	// 2006 debug
	//if (ret)
	if (true)
		{
		HRESULT hr;

		// Re-intialize Multi-Query Interface:
		for (int i = 0; i < sizeof (m_arrMultiQI) / sizeof (MULTI_QI); i++)
			{
			m_arrMultiQI [i].pItf = NULL;
			m_arrMultiQI [i].hr = 0;
			}

		// Load up the Interface ID's we hope to get pointers for when we
		// call CoCreateInstanceEx():
		m_arrMultiQI [MQI_IOPCSERVER].pIID		= &IID_IOPCServer;
		m_arrMultiQI [MQI_IOPCCOMMON].pIID		= &IID_IOPCCommon;
		m_arrMultiQI [MQI_IOPCCONNPT].pIID		= &IID_IConnectionPointContainer;
		m_arrMultiQI [MQI_IOPCITEMPROP].pIID	= &IID_IOPCItemProperties;
		m_arrMultiQI [MQI_IOPCBROWSE].pIID		= &IID_IOPCBrowseServerAddressSpace;
		m_arrMultiQI [MQI_IOPCPUBLIC].pIID		= &IID_IOPCServerPublicGroups;
		m_arrMultiQI [MQI_IOPCPERSIST].pIID		= &IID_IPersistFile;

		// Connect to the OPC Server and query all possible interfaces:
		if (m_strRemoteMachine.IsEmpty ())
			{
			// Since m_strRemoteMachine is empty, we will try to instantiate
			// the OPC Server on our local machine.  

			// CoCreateInstanceEx will launch the OPC Server if necessary, and
			// call its QueryInterface for us (bumping its reference count):
			hr = CoCreateInstanceEx (
				clsid,										// CLSID
				NULL,										// No aggregation
				CLSCTX_SERVER,								// connect to local, inproc and remote servers
				NULL,										// remote machine name 
				sizeof (m_arrMultiQI) / sizeof (MULTI_QI),	// number of IIDS to query		
				m_arrMultiQI);								// array of IID pointers to query
			}
		else
			{
			// Since m_strRemoteMachine is not empty, we will assume it contains
			// a valid remote machine name.  We will try to instantiate the OPC
			// Server object on the machine with that name.

			// First we need to initialize a server info structure:
			COSERVERINFO tCoServerInfo;
			ZeroMemory (&tCoServerInfo, sizeof (tCoServerInfo));

			// Allocate memory for the machine name string:
			int nSize = m_strRemoteMachine.GetLength () * sizeof (WCHAR);
			tCoServerInfo.pwszName = new WCHAR [nSize];

			// Check validity of pointer.  If it's bad, there's no point in continuing:
			if (!tCoServerInfo.pwszName)
				{
				ASSERT (FALSE);
				return (false);
				}

			// Copy the machine name string into the server info structure:
#ifdef _UNICODE
			// For Unicode builds, the contents of m_strRemoteMachine will
			// already be in wide character format, as demanded by COM, so
			// copy it as is.
			lstrcpyn (tCoServerInfo.pwszName, m_strRemoteMachine, nSize);
#else 
			// For ANSI builds, the contents of m_strRemoteMachine will not
			// be in wide character format, as demanded by COM, so we need
			// to reformat:
			mbstowcs (tCoServerInfo.pwszName, m_strRemoteMachine, nSize);
#endif//_UNICODE

			// CoCreateInstanceEx will launch the OPC Server if necessary, and
			// call its QueryInterface for us (bumping its reference count):
			hr = CoCreateInstanceEx (
				clsid,										// CLSID
				NULL,										// No aggregation
//				CLSCTX_SERVER,								// connect to local, inproc and remote servers
				CLSCTX_REMOTE_SERVER,						// lyy
				&tCoServerInfo,								// remote machine name 
				sizeof (m_arrMultiQI) / sizeof (MULTI_QI),	// number of IIDS to query		
				m_arrMultiQI);								// array of IID pointers to query

			// COM requires us to free memory allocated for [out] and [in/out]
			// arguments (i.e. name string).
			delete [] tCoServerInfo.pwszName;
			}

		// If CoCreateInstanceEx succeeded, we can check the returned 
		// interface pointers and save them as member variables:

		if (SUCCEEDED (hr))	
			{
			TRACE (_T("OTC: Initializing server %s interfaces.\r\n"), GetProgID ());

			// Check IOPCServer interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCSERVER].hr))
				{
				m_pIServer = (IOPCServer *)m_arrMultiQI [MQI_IOPCSERVER].pItf;

				if (m_pIServer == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCSERVER].pItf != NULL)
					{
					// Warning failure but pointer not set to null
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IOPCServer (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCSERVER].hr); 
				}

			// Check IOPCCommon interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCCOMMON].hr))
				{
				m_pICommon = (IOPCCommon *)m_arrMultiQI [MQI_IOPCCOMMON].pItf;

				if (m_pICommon == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCCOMMON].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IOPCCommon (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCCOMMON].hr); 
				}

			// Check IConnectionPointContainer interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCCONNPT].hr))
				{
				m_pIConnPtContainer = 
					(IConnectionPointContainer *)m_arrMultiQI [MQI_IOPCCONNPT].pItf;

				if (m_pIConnPtContainer == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCCONNPT].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IConnectionPoint (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCCONNPT].hr); 
				}

			// Check IOPCItemProperties interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCITEMPROP].hr))
				{
				m_pIItemProps = 
					(IOPCItemProperties *)m_arrMultiQI [MQI_IOPCITEMPROP].pItf;

				if (m_pIItemProps == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCITEMPROP].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IOPCItemProperties (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCITEMPROP].hr); 				
				}

			// Check IOPCBrowseServerAddressSpace interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCBROWSE].hr))
				{
				m_pIBrowse = 
					(IOPCBrowseServerAddressSpace *)m_arrMultiQI [MQI_IOPCBROWSE].pItf;

				if (m_pIBrowse == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCBROWSE].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IOPCBrowseServerAddressSpace (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCBROWSE].hr); 				
				}

			// Check IOPCServerPublicGroups interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCPUBLIC].hr))
				{
				m_pIPublicGroups = 
					(IOPCServerPublicGroups *)m_arrMultiQI [MQI_IOPCPUBLIC].pItf;

				if (m_pIPublicGroups == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCPUBLIC].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IOPCServerPublicGroups (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCPUBLIC].hr); 				
				}

			// Check IPersistFile interface pointer:
			if (SUCCEEDED (m_arrMultiQI [MQI_IOPCPERSIST].hr))
				{
				m_pIPersistFile = 
					(IPersistFile *)m_arrMultiQI [MQI_IOPCPERSIST].pItf;

				if (m_pIPersistFile == NULL)
					{
					// Warning success but no valid pointer:
					ASSERT (FALSE);
					}
				}
			else
				{
				if (m_arrMultiQI [MQI_IOPCPERSIST].pItf != NULL)
					{
					// Warning failure but pointer not set to null:
					ASSERT (FALSE);
					}

				TRACE (_T("OTC: Failed to query IPersistsFile (%08X).\r\n"), 
					m_arrMultiQI [MQI_IOPCPERSIST].hr); 				
				}

			// Check IConnectionPointContainer interface pointer:
			if (m_pIConnPtContainer != NULL)
				{
				// If the server supports the shutdown interface, provide a sink 
				// to the server.

				// Get connection point pointer:
				IConnectionPoint *pCP = NULL;
				hr = m_pIConnPtContainer->FindConnectionPoint (IID_IOPCShutdown, &pCP);

				// If we got the connection point, instantiate our shutdown sink:
				if (SUCCEEDED (hr))
					{
					try
						{
						// Instantiate the shutdown sink and add us to its reference count:
						m_pIShutdownSink = new IKShutdownSink (this);
						m_pIShutdownSink->AddRef ();
												
						// Give the connection point a pointer to our shutdown sink:
						// (m_dwCookieShutdownSink is a returned token that uniquely
						// identifies this connection.)
						hr = pCP->Advise (m_pIShutdownSink, &m_dwCookieShutdownSink);

						// We are done with the connection point, so release our reference:
						pCP->Release ();
						}
					
					catch (...)
						{
						// If we find ourselves here, either "new" failed or pCP is bad.
						ASSERT (FALSE);
						hr = E_FAIL;
						}
					}
				}

			// We will base our success on the validity of the IOPCServer interface
			// pointer.  If it is invalid, then we won't be able do do anyting:
			m_bConnected = (m_pIServer != NULL);

			// Log success or failure:
			if (m_bConnected)
				LogMsg (IDS_SERVER_CONNECT_SUCCESS, GetProgID ());
			else
				LogMsg (IDS_SERVER_REQUIRED_IID_UNSUPPORTED, GetProgID (), hr);
			}
		
		// CoCreateInstanceEx failed:
		else
			{
			// log failure
			LogMsg (IDS_SERVER_CONNECT_FAILURE, GetProgID (), hr);
			}
		}
	
	// Failed to get Class ID:
	else
		{
		// Log failure:
		LogMsg (IDS_SERVER_UNABLE_TO_GET_CLSID, GetProgID ());
		}

	// Return connected state:
	return (m_bConnected);
	}