///////////////////////////////////////////////////////////////////////////// // 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; }
// ************************************************************************** // 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); }
///////////////////////////////////////////////////////////////// // 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; }
//////////////////////////////////////////////////////////////// // 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; }
//////////////////////////////////////////////////////////////// // 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; }
// ************************************************************************** // 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); } }
// ************************************************************************** // 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 ()); } }
// ************************************************************************** // 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; } }
// ************************************************************************** // 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); }