📄 document.cpp
字号:
// **************************************************************************
// document.cpp
//
// Description:
// Implements a CDocument derived class. This is the document part of our
// MFC SDI document/view architecture.
//
// DISCLAIMER:
// This programming example is provided "AS IS". As such Kepware, Inc.
// makes no claims to the worthiness of the code and does not warranty
// the code to be error free. It is provided freely and can be used in
// your own projects. If you do find this code useful, place a little
// marketing plug for Kepware in your code. While we would love to help
// every one who is trying to write a great OPC client application, the
// uniqueness of every project and the limited number of hours in a day
// simply prevents us from doing so. If you really find yourself in a
// bind, please contact Kepware's technical support. We will not be able
// to assist you with server related problems unless you are using KepServer
// or KepServerEx.
// **************************************************************************
#include "stdafx.h"
#include "opctestclient.h"
#include "document.h"
#include "server.h"
#include "serverpropertysheet.h"
#include "group.h"
#include "grouppropertysheet.h"
#include "item.h"
#include "itemadddlg.h"
#define LARGE_ADDITEM_COUNT 64
/////////////////////////////////////////////////////////////////////////////
// CKDocument
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE (CKDocument, CDocument)
// **************************************************************************
BEGIN_MESSAGE_MAP (CKDocument, CDocument)
END_MESSAGE_MAP ()
/////////////////////////////////////////////////////////////////////////////
// CKDocument construction/destruction
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// CKDocument ()
//
// Description:
// Constructor
//
// Parameters:
// none
//
// Returns:
// none
// **************************************************************************
CKDocument::CKDocument ()
{
// Initialize member variables:
m_pServerHead = NULL;
m_cdwServers = 0;
m_pCurSelServer = NULL;
m_pCurSelGroup = NULL;
m_bLocked = false;
}
// **************************************************************************
// ~CKDocument ()
//
// Description:
// Destructor
//
// Parameters:
// none
//
// Returns:
// none
// **************************************************************************
CKDocument::~CKDocument ()
{
}
// **************************************************************************
// SetLocked ()
//
// Description:
// Locks the document object.
//
// Parameters:
// bool bSet Set to "true" to lock, "false" to unlock
//
// Returns:
// void
// **************************************************************************
void CKDocument::SetLocked (bool bSet)
{
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&m_csDoc);
// Use a flag to indicate locked state:
m_bLocked = bSet;
}
// **************************************************************************
// IsLocked ()
//
// Description:
// Returns the locked state of document object.
//
// Parameters:
// none
//
// Returns:
// bool - true if locked.
// **************************************************************************
bool CKDocument::IsLocked ()
{
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&m_csDoc);
// Return locked state:
return (m_bLocked);
}
// **************************************************************************
// OnNewDocument ()
//
// Description:
// New document event handler.
//
// Parameters:
// none
//
// Returns:
// BOOL - TRUE if success.
// **************************************************************************
BOOL CKDocument::OnNewDocument ()
{
// Perform default processing:
if (!CDocument::OnNewDocument ())
return (FALSE);
// SDI documents reuse this document so perform reinitialization:
SetModified (FALSE);
return (TRUE);
}
// **************************************************************************
// OnOpenDocument ()
//
// Description:
// Open document event handler.
//
// Parameters:
// none
//
// Returns:
// BOOL - TRUE if success.
// **************************************************************************
BOOL CKDocument::OnOpenDocument (LPCTSTR lpszPathName)
{
// Perform default processing:
if (!CDocument::OnOpenDocument (lpszPathName))
return (FALSE);
// Must do some additional work if we have a server object:
if (m_pServerHead)
{
// Update status bar text to indicate we are loading project:
CKStatusBarText cText (IDS_LOADING_PROJECT);
// Update all views so the user can see progress:
UpdateAllViews (NULL, HINT_LOAD_PROJECT, m_pServerHead);
// Build a list of servers to load to pass along to a worker thread
// for processing:
CObArray cServerList;
// Catch memory exceptions that could get thrown by object array:
try
{
// Allocate memory for array of server objects:
cServerList.SetSize (m_cdwServers);
// Create a CKServer pointer and set it to first server in linked list:
CKServer *pServer = m_pServerHead;
// Loop over servers in linked list:
for (DWORD dw = 0; dw < m_cdwServers; dw++)
{
// Put pointer to server in object array:
ASSERT (pServer);
cServerList [dw] = (CObArray *)pServer;
// Get next server in linked list:
pServer = pServer->GetNext ();
}
ASSERT (pServer == NULL); // list and count in sync ?
}
catch (CMemoryException *e)
{
// If memory exception thrown, delet exception object and return FALSE
// to indicate failure.
e->Delete ();
return (FALSE);
}
// Fill a structre to pass along to worker thread. Structure will
// contain a pointer to out list of servers and task specification
// (start multiple servers).
WORKERTHREADARG tArg;
tArg.eTask = WORKERTHREADARG::START_MULTIPLE_SERVER;
tArg.pvObjectA = (void *)&cServerList;
// Run the worker thread to start all server connections:
RunWorkerThread (&tArg);
}
// If we make it here, all went OK, so return TRUE:
return (TRUE);
}
// **************************************************************************
// DeleteContents ()
//
// Description:
// Reset the document object for reuse. This includes disconnect from all
// OPC servers and deleting all server objects.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKDocument::DeleteContents ()
{
// Create a wait cursor object. This will cause the wait cursor,
// usually an hourglass, to be displayed. When this object goes
// out of scope, its destructor will restore the previous cursor
// type.
CWaitCursor wc;
// Update status bar text to indicate that we are unloading project:
CKStatusBarText cText (IDS_UNLOADING_PROJECT);
// Notify all views that the project is closing so that no request for
// server/group/item is made (as in OnGetDispInfo) for a deleted object:
UpdateAllViews (NULL, HINT_CLOSE_PROJECT, NULL);
// Free all server connections maintained by the document. Start with
// head of linked list and work our way to end:
while (m_pServerHead)
{
// Need to make a copy of current head of linked list:
CKServer *pServer = m_pServerHead;
// Reset linked list head to next server:
m_pServerHead = pServer->GetNext ();
// Delete server (previously the head of linked list):
RemoveServer (pServer);
}
// Check that we deleted all servers in linked list (debug only):
ASSERT (m_cdwServers == 0);
// Invalidate currently selected server and group:
m_pCurSelServer = NULL;
m_pCurSelGroup = NULL;
// Default processing:
CDocument::DeleteContents ();
}
// **************************************************************************
// SetModified ()
//
// Description:
// Set the document modified flag. Update title bar to signal that document
// has been modified.
//
// Parameters:
// bool bModified Set to "true" if document has been modified.
//
// Returns:
// void
// **************************************************************************
void CKDocument::SetModified (bool bModified /* = true */)
{
// If we are currently unmodified, we may need to add or remove an
// asterisk from title bar. (The framework automatically clears the
// asterisk when saving the document):
if (!IsModified ())
{
// Get document title:
CString strTitle = GetTitle ();
// If we are modifying, see if we should add asterisk:
if (bModified)
{
// If we can't find an asterisk in title, we need to add one:
if (strTitle.Find (_T(" *")) < 0)
{
strTitle += " *";
SetTitle (strTitle);
}
}
// Otherwise, remove asterisk if any:
else
{
// If we can find an asterisk in title, we need to remove it:
if (strTitle.Find (_T(" *")) >= 0)
{
strTitle.TrimRight (_T(" *"));
SetTitle (strTitle);
}
}
}
// Set modified flag:
SetModifiedFlag (bModified);
}
// **************************************************************************
// OnServerShutdown ()
//
// Description:
// Server shutdown event handler.
//
// Parameters:
// CKServer *pServer Pointer to server that has given us a
// shutdown notification.
//
// Returns:
// void
// **************************************************************************
void CKDocument::OnServerShutdown (CKServer *pServer)
{
ASSERT (pServer != NULL);
// Shutdown the server:
pServer->Stop ();
// Refresh our group view so that new active status is shown:
UpdateAllViews (NULL, HINT_REFRESH_GROUPVIEW, NULL);
}
////////////////////////////////////////////////////////////////////////////
// CKDocument serialization
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// Serialize ()
//
// Description:
// Save or load project settings.
//
// Parameters:
// CArchive &ar The archive to save or load project settings.
//
// Returns:
// void
// **************************************************************************
void CKDocument::Serialize (CArchive &ar)
{
// Be prepared to catch exceptions:
try
{
// Save project:
if (ar.IsStoring ())
{
// Save the number of server object first so we will know how
// many to load later:
ar << m_cdwServers;
// Now serialize each server object. Start with head of linked
// list and work our way to end:
CKServer *pServer = m_pServerHead;
// Keep looping until we hit end of linked list, indicated by
// a NULL pointer:
while (pServer)
{
// Serialize server object:
pServer->Serialize (ar);
// Get pointer to next server in linked list:
pServer = pServer->GetNext ();
}
}
// Else load project:
else
{
// First get the number of servers to load:
DWORD cdwServers;
ar >> cdwServers;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -