📄 group.cpp
字号:
pItem->SetItemID (szFieldText);
break;
case CSV_AccessPath:
// Item Access Path:
pItem->SetAccessPath (szFieldText);
break;
case CSV_DataType:
// Item Data Type. (Need to convert string to variant type.)
pItem->SetDataType (VartypeFromString (szFieldText));
break;
case CSV_Active:
// Item Active state. (Need to convert string to bool type.)
if (lstrcmpi (szFieldText, _T("TRUE")) == 0)
pItem->SetActive (true);
else
pItem->SetActive (false);
break;
default:
// Unexpected field type ID. Programmer error.
ASSERT (FALSE);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
// CKGroup construction/destruction
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// CKGroup ()
//
// Description:
// Constructor.
//
// Parameters:
// CKServer *pParent Pointer to parent server object
//
// Returns:
// none
// **************************************************************************
CKGroup::CKGroup (CKServer *pParent)
{
ASSERT (pParent != NULL);
m_pServer = pParent;
// Initialize member variables.
// OPC Group properties:
m_strName = GROUP_DEFAULT_NAME;
m_dwUpdateRate = GROUP_DEFAULT_UPDATERATE;
m_dwLanguageID = GROUP_DEFAULT_LANGUAGEID;
m_lBias = GROUP_DEFAULT_TIMEBIAS;
m_fDeadband = GROUP_DEFAULT_DEADBAND;
m_bActive = GROUP_DEFAULT_ACTIVESTATE;
m_dwUpdateMethod = GROUP_DEFAULT_UPDATEMETHOD;
m_hServer = NULL;
m_bValid = FALSE;
// Flags:
ZeroMemory (&m_bfFlags, sizeof (m_bfFlags));
// Item management:
m_pPrev = NULL;
m_pNext = NULL;
m_pItemHead = NULL;
m_cdwItems = 0;
// GUI management:
m_hTreeItem = NULL;
// Interface pointers we will query and maintain:
m_pIGroupState = NULL;
m_pIPublicGroupState = NULL;
m_pIItemMgt = NULL;
m_pISync = NULL;
m_pIAsync = NULL;
m_pIDataObject = NULL;
m_pIAsync2 = NULL;
m_pIConnPtContainer = NULL;
m_pIDataSink20 = NULL;
m_dwCookieDataSink20 = 0;
m_pIAdviseSink = NULL;
m_dwCookieRead = 0;
m_dwCookieWrite = 0;
}
// **************************************************************************
// // ~CKGroup ()
//
// Description:
// Destructor
//
// Parameters:
// none
//
// Returns:
// none
// **************************************************************************
CKGroup::~CKGroup ()
{
// Assert that all interfaces and items have been properly released:
ASSERT (m_cdwItems == 0);
ASSERT (m_pIGroupState == NULL);
ASSERT (m_pIPublicGroupState == NULL);
ASSERT (m_pIItemMgt == NULL);
ASSERT (m_pISync == NULL);
ASSERT (m_pIAsync == NULL);
ASSERT (m_pIDataObject == NULL);
ASSERT (m_pIAsync2 == NULL);
ASSERT (m_pIConnPtContainer == NULL);
ASSERT (m_pIDataSink20 == NULL);
ASSERT (m_dwCookieDataSink20 == 0);
ASSERT (m_pIAdviseSink == NULL);
ASSERT (m_dwCookieRead == 0);
ASSERT (m_dwCookieWrite == 0);
}
/////////////////////////////////////////////////////////////////////////////
// CKGroup item management
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// AddItemToList ()
//
// Description:
// Add an item to this group.
//
// Parameters:
// CKItem *pItem Pointer to item object to add.
//
// Returns:
// void
// **************************************************************************
void CKGroup::AddItemToList (CKItem *pItem)
{
// New items are added to the head of the linked list.
// That means new the items's "next" item is old head of list,
pItem->SetNext (m_pItemHead);
// and the new item is the old head of list's "previous" item,
if (m_pItemHead)
m_pItemHead->SetPrev (pItem);
// and that new item is now the new "head" of list.
m_pItemHead = pItem;
// Don't forget to bump up our local item count,
++m_cdwItems;
// and the global item count.
UpdateItemCount (+1);
}
// **************************************************************************
// RemoveItemFromList ()
//
// Description:
// Remove an item from this group.
//
// Parameters:
// CKItem *pItem Pointer to item object to remove. If NULL, all
// items will be removed.
//
// Returns:
// void
// **************************************************************************
void CKGroup::RemoveItemFromList (CKItem *pItem)
{
// Remove all items:
if (pItem == NULL)
{
// Start with head of linked list and work our way up:
pItem = m_pItemHead;
// Loop over items until we hit the end of the list (where
// pItem will be NULL).
while (pItem)
{
// Must save the next item before we delete item. The next
// item will become the new head of list.
m_pItemHead = pItem->GetNext ();
// Delete item:
delete pItem;
// Process next item (the new head of list):
pItem = m_pItemHead;
}
// Update global item count,
UpdateItemCount (-(int)m_cdwItems);
// and reset our local count,
m_cdwItems = 0;
}
// Remove a single item:
else
{
// To remove a link, we must first get pointers to the adjacent links:
CKItem *pPrev = pItem->GetPrev ();
CKItem *pNext = pItem->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 (pItem == m_pItemHead)
m_pItemHead = pNext;
// Decrement our local item count,
--m_cdwItems;
// and the global item count.
UpdateItemCount (-1);
}
}
// **************************************************************************
// AddItems ()
//
// Description:
// Called to add multiple OPC Items at one time. A CKItem will be added to
// this object if needed and a request to add a corresponding OPC Item to
// the OPC Group will be made.
//
// Parameters:
// CObArray &cItemList Array of item objects to add.
// DWORD dwCount Number of items in cItemList.
// bool bLoadingProject Set to true if call is made during project
// load so item can be added to this object's
// imem list. Otherwise we will assume item
// already exists in list, and only needs to
// added to OPC Group.
//
// Returns:
// void
// **************************************************************************
void CKGroup::AddItems (CObArray &cItemList, DWORD dwCount, bool bLoadingProject /* = false */)
{
CKItem *pItem = NULL;
DWORD dwIndex = 0;
ASSERT (dwCount > 0);
// If the item is new add it to our list:
if (!bLoadingProject)
{
// Add the list of items to our project whether we they are valid or not:
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
// Get pointer to item in input array:
pItem = (CKItem *) cItemList [dwIndex];
ASSERT (pItem != NULL);
// Add it to our list:
AddItemToList (pItem);
}
}
// If we are connected to an OPC Server, and have a pointer to its IOPCItemMgt
// interface, then issue an "add items" request:
if ((m_pServer->IsConnected ()) && (m_pIItemMgt != NULL))
{
HRESULT hr;
OPCITEMDEF *pItemArray = NULL;
OPCITEMRESULT *pResults = NULL;
HRESULT *pErrors = NULL;
DWORD dwLen;
DWORD cdwSuccess = 0;
// Allocate memory for item definition array:
pItemArray = (OPCITEMDEF *) CoTaskMemAlloc (dwCount * sizeof (OPCITEMDEF));
// Don't bother if memory allocation failed:
if (pItemArray != NULL)
{
// Fill the item definition array:
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
// Get pointer to item in input array:
pItem = (CKItem *) cItemList [dwIndex];
ASSERT (pItem != NULL);
// COM requires that all string be in wide character format. The
// access path and Item ID properties are strings, so we may have
// to convert their format.
// First get the length of access path string:
dwLen = lstrlen (pItem->GetAccessPath ());
if (dwLen)
{
// Allocate memory for string:
pItemArray [dwIndex].szAccessPath = (WCHAR *) CoTaskMemAlloc ((dwLen + 1) * sizeof (WCHAR));
#ifdef _UNICODE
// If Unicode build, string will already be in wide character
// format, so copy into allocated memory as is:
lstrcpyn (pItemArray [dwIndex].szAccessPath, pItem->GetAccessPath (), dwLen + 1);
#else
// If ANSI build, then string format needs to be converted. Place
// result of conversion into allocated memory:
MultiByteToWideChar (CP_ACP, 0, pItem->GetAccessPath (), -1, pItemArray [dwIndex].szAccessPath, dwLen + 1);
#endif
}
else
{
// Access path string length is zero, so set output to NULL:
pItemArray [dwIndex].szAccessPath = NULL;
}
// Multibyte to wide character conversion for Item ID:
dwLen = lstrlen (pItem->GetItemID ()); // This can't be zero, so no test as above
pItemArray [dwIndex].szItemID = (WCHAR *) CoTaskMemAlloc ((dwLen + 1) * sizeof (WCHAR));
#ifdef _UNICODE
lstrcpyn (pItemArray [dwIndex].szItemID, pItem->GetItemID (), dwLen + 1);
#else
MultiByteToWideChar (CP_ACP, 0, pItem->GetItemID (), -1, pItemArray [dwIndex].szItemID, dwLen + 1);
#endif
// Set remaining structure members:
// (If requested data type is NULL, the OPC Server should return
// the default type. The returned canonical data type may not be
// the same as the requested data type.)
pItemArray [dwIndex].bActive = pItem->IsActive (); // active state
pItemArray [dwIndex].hClient = (OPCHANDLE) pItem; // our handle to item
pItemArray [dwIndex].dwBlobSize = 0; // no blob support
pItemArray [dwIndex].pBlob = NULL;
pItemArray [dwIndex].vtRequestedDataType = pItem->GetDataType (); // Requested data type
}
// Issue request add items request through IOPCItemMgt interface:
hr = m_pIItemMgt->AddItems (
dwCount, // Item count
pItemArray, // Array of item definition structures
&pResults, // Result array
&pErrors); // Error array
// Check results for each item:
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
// Get pointer to item in input array:
pItem = (CKItem *) cItemList [dwIndex];
ASSERT (pItem != NULL);
// Everything looks good:
if (SUCCEEDED (hr) && (pErrors && SUCCEEDED (pErrors [dwIndex])))
{
// Set CKItem valid:
pItem->SetValid (TRUE);
// Update CKItem properties:
// (Note, the returned canonical data type may not be the same
// as the requested data type.)
pItem->SetServerHandle (pResults [dwIndex].hServer);
pItem->SetDataType (pResults [dwIndex].vtCanonicalDataType);
pItem->SetAccessRights (pResults [dwIndex].dwAccessRights);
// If the server passed back a blob, it is our responsibilty
// to free it. (Wrap with exception handler in case they were
// bad and did not initialize the blob pointer.)
try
{
if (pResults [dwIndex].pBlob != NULL)
CoTaskMemFree (pResults [dwIndex].pBlob);
}
catch (...)
{
// Probably hit a bad pointer. Try to process next item.
TRACE (_T("OTC: AddItems exception thrown from freeing invalid blob.\r\n"));
}
// Bump success count:
++cdwSuccess;
}
// There were errors:
else
{
// Log error message:
if (pErrors && FAILED (pErrors [dwIndex]))
{
// We have a good error array, so use it's HRESULT value.
// (We could use GetErrorString() to get use friendly text if
// we wish.)
LogMsg (IDS_GROUP_ADD_ITEMS_FAILED, pItem->GetItemID (), GetName (),
pErrors [dwIndex]);
}
else
{
// Error array does not look good. Use HRESULT value returned by add
// item call. (Again we could use the GetErrorString() if we wish.)
LogMsg (IDS_GROUP_ADD_ITEMS_FAILED, pItem->GetItemID (), GetName (), hr);
}
// Set item invalid:
pItem->SetValid (FALSE);
// Use NULL server handle for invalid items:
pItem->SetServerHandle (NULL);
}
// COM requires us to free memory allocated for [out] and [in/out]
// arguments (i.e. access path and item id strings):
if (pItemArray [dwIndex].szAccessPath)
CoTaskMemFree (pItemArray [dwIndex].szAccessPath);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -