📄 impiopcbrowseserveraddressspace.cpp
字号:
break;
} // END switch (dwBrowseFilterType)
///////////////////////////////////////
//
// OK, not we have a Map containing pointers to all of the valid
// strings to be returned, so let's build an array of LPOLESTR and
// create an enumerator to return to the caller
//
///////////////////////////////////////
// Make sure that everything jives together.
//
ASSERT(mapStrings.GetCount() == lNumEntries);
// Make sure that we got something to work with
//
if (0L == lNumEntries)
{
FreeMapMemory(&mapStrings);
return CreateEmptyStringEnumerator(ppIEnumString);
}
// Allocate our memory for the list of string names
//
ppStringArray = new LPOLESTR [lNumEntries];
if (NULL == ppStringArray)
{
*ppIEnumString = NULL;
FreeMapMemory(&mapStrings);
return E_OUTOFMEMORY;
}
// Fill the LPOLESTR array with the pointers that contain the strings.
// This array will be used to create the enumerator.
//
posMap = mapStrings.GetStartPosition();
for (long i = 0; i < lNumEntries; i++)
{
mapStrings.GetNextAssoc(posMap, lHandle, pwcString);
ppStringArray[i] = pwcString;
mapStrings.RemoveKey(lHandle);
}
// Create the enumerator
//
pEnumString = new CImpIEnumString (NULL, // Parent
(ULONG)lNumEntries, // # strings in enum
ppStringArray, // Enum string array
pIMalloc); // IMalloc pointer
if (NULL == pEnumString)
{
*ppIEnumString = NULL;
return E_OUTOFMEMORY;
}
pEnumString->AddRef();
// There shouldn't be anything in the map at this point, but just in case...
//
FreeMapMemory(&mapStrings);
// Free the memory for the temp string array because the enumerator keeps its
// own local copy.
//
for (i = 0; i < lNumEntries; i++)
{
delete [] ppStringArray[i];
}
delete [] ppStringArray;
// Call QueryInterface() to get an interface pointer for the client. This will
// do an AddRef() internally, so we don't need to explicitly do one.
//
hr = pEnumString->QueryInterface(IID_IEnumString, (LPVOID *)ppIEnumString);
if (FAILED(hr))
{
pEnumString->Release();
*ppIEnumString = NULL;
return E_FAIL;
}
// Reset the new enumerator and release our copy of it
//
(*ppIEnumString)->Reset();
pEnumString->Release();
return S_OK;
}
////////////////////////////////////////////////////////////////
// CImpIOPCBrowseServer::GetItemID()
//
// @desc This function will assemble a fully qualified ItemID in the
// hierarchial address space. The ItemID we return is dependant
// on the browse level the the user is on. If they are on the
// driver level, we simply return the string they passed to us.
// If we are on the device level, we append the string passed
// to us to the end of the driver name. If we are on the
// datablock level, we build a string with the driver name,
// device name and then string they passed to us.
// The driver name and device name are known because the user
// would have called ChangeBrowsePosition() and "drilled" into
// those names.
// The name passed into this function through the
// szItemDataID parameter is not verified to be correct. This
// is because if this string is a datablock address, it would
// be very driver specific to verify if this datablock address
// is found in the driver. Since this is a generic server, we
// won't try and verify it.
//
// @parm [in] LPCWSTR | szItemDataID | Current branch or leaf
// @parm [out, string] LPCWSTR * | ppszItemID | Returned item id
//
// @retval S_OK success
// @retval E_FAIL failure
// @retval E_INVALIDARG an invalid parameter was passed
// @retval E_OUTOFMEMORY out of memory
//
// TODO: Add any browse levels, etc required to return a fully
// qualified item id.
//
// @devnote The datablock level returns hints, so a hint id passed into
// GetItemID() will not return an item id that will pass when
// added through AddItems().
//
////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIOPCBrowseServer::GetItemID(LPWSTR szItemDataID,
LPWSTR *ppszItemID)
{
CString szTmpItemID;
WCHAR *pwcTemp = NULL;
int nLength = 0;
// Make sure we didn't get a bad pointer.
//
if ((NULL == ppszItemID) ||
(NULL == szItemDataID))
{
return E_INVALIDARG;
}
//////////////////////////////////////////////////////////////
//
// TODO: You may need to modify the following code.
// This code assumes that the final browse level (DATABLOCK_LEVEL)
// returns a hint address to the client. So, the client passes in
// that hint address for the server to return a fully-qualified item
// id. Your driver's address space may be different, so you may need
// to addjust what is returned at the following 2 levels.
//
// For example, if the final level of brosing returns a parameter
// name (such as "ProcessVariable" or "SetPoint", then you can remove
// the search for the HINT_DELIM in the DATABLOCK_LEVEL.
//
//////////////////////////////////////////////////////////////
// Build the string dependant on the current browse level.
//
switch(this->m_dwLevel)
{
case DEVICE_LEVEL:
// We simply return the passed string here. This id would fail if
// passed to AddItems()
//
szTmpItemID = szItemDataID;
break;
case DATABLOCK_LEVEL:
szTmpItemID = m_szDeviceName;
szTmpItemID += IOADDRESS_DELIM;
szTmpItemID += szItemDataID;
// We need to return a fully qualified item id, so
// since we work with hints, simply strip off the hint stuff and
// return the start address of the hint.
//
if (-1 != (nLength = szTmpItemID.Find(HINT_DELIM)))
{
szTmpItemID = szTmpItemID.Left(nLength);
}
break;
default:
// Should never happen!!
*ppszItemID = NULL;
TRACE("Invalid Browse Level (%lu), File %s, Line %d\n",
m_dwLevel, __FILE__, __LINE__);
return E_FAIL;
break;
}
// Remove any whitespace (just in case)
//
szTmpItemID.TrimLeft();
szTmpItemID.TrimRight();
// Macro required for ATL string conversions
//
USES_CONVERSION;
// Convert to a wide-character string
//
nLength = szTmpItemID.GetLength() + 1; // add 1 for the NULL
pwcTemp = A2W(szTmpItemID.GetBuffer(nLength));
szTmpItemID.ReleaseBuffer();
// Allocate the memory for the assembled ItemID.
//
*ppszItemID = (WCHAR *)pIMalloc->Alloc(sizeof(WCHAR) * nLength);
if (NULL == *ppszItemID)
{
return E_OUTOFMEMORY;
}
// Copy the string to be returned to the caller.
//
wcscpy(*ppszItemID, pwcTemp);
return S_OK;
}
////////////////////////////////////////////////////////////////
// CImpIOPCBrowseServer::BrowseAccessPaths()
//
// @desc This function is currently not required and simply returns E_NOTIMPL
//
// @parm [in, string] LPCWSTR | szItemID | Fully qualified Item ID
// @parm [out] LPENUMSTRING *| ppIEnumString | Where to save the returned
// string enumerator. This parameter
// must be NULL is the HRESULT return is
// anything other than S_OK.
//
// @retval E_FAIL The function failed
// @retval E_INVALIDARG A bad parameter was passed (i.e. a NULL pointer)
// @retval S_FALSE There is nothing to enumerate
// @retval E_OUTOFMEMORY A memory allocator failed (not enough memory)
// @retval S_OK Success
// @retval E_NOTIMPL The server does not require or support access paths
//
// @devnote Refer to the OLE for Process Control Standard v1.0a for more information
//
// TODO: If your driver requires access path support, then you need
// to implement this function so an OPC client can browse
// the available access paths for a given item id.
//
////////////////////////////////////////////////////////////////
STDMETHODIMP CImpIOPCBrowseServer::BrowseAccessPaths(LPCWSTR szItemID,
LPENUMSTRING *ppIEnumString)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////
//
// Internal utility functions that are not part of the
// IOPCBrowseServerAddressSpace interface.
//
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// CImpIOPCBrowseServer::BrowseHierarchial()
//
// @desc
//
// @parm CLongPtrMap * | pMap | Map to store strings
// @parm long * | plNumEntries | Number of entries returned in map
// @parm OPCBROWSETYPE | dwBrowseFilterType| Browse filter (Branch or Leaf)
// @parm CString | szFilterCriteria | Filtering string
// @parm FILTERTYPE | dwFilterType | Filtering type
//
// @retval S_OK success
// @retval E_FAIL failure
// @retval E_INVALIDARG an invalid parameter was passed
// @retval E_OUTOFMEMORY out of memory
//
////////////////////////////////////////////////////////////////
HRESULT CImpIOPCBrowseServer::BrowseHierarchial(CLongPtrMap *pMap,
long *plNumEntries,
OPCBROWSETYPE dwBrowseFilterType,
CString szFilterCriteria,
FILTERTYPE dwFilterType)
{
HRESULT hr;
//////////////////////////////////////////////////////////////
//
// TODO: Add any additional browsing levels here that your
// driver supports.
//
//////////////////////////////////////////////////////////////
switch(m_dwLevel)
{
case DEVICE_LEVEL:
hr = GetDeviceList(pMap, // Map to store the strings in
plNumEntries, // Number of entries in the map
dwBrowseFilterType, // Browse Filter
szFilterCriteria, // String used for filtering
dwFilterType); // Filter type
break;
case DATABLOCK_LEVEL:
hr = GetDatablockList(pMap, // Map to store the strings in
plNumEntries, // Number of entries in the map
m_szDeviceName, // Device name to browse into
dwBrowseFilterType, // Browse Filter
szFilterCriteria, // String used for filtering
dwFilterType); // Filter type
break;
default:
// Should never happen!!
TRACE("Invalid Browse Level (%lu), File %s, Line %d\n",
m_dwLevel, __FILE__, __LINE__);
return E_FAIL;
break;
} // END switch(this->m_dwLevel)
return hr;
}
////////////////////////////////////////////////////////////////
// CImpIOPCBrowseServer::BrowseFlat()
//
// @desc This function performs a "flat" browse at the current level.
// It will return all branches and leafs as fully qualified
// item ids (except when hints are returned)
//
// @parm CLongPtrMap * | pMap | Map to store strings
// @parm long * | plNumEntries | Number of entries returned in map
// @parm CString | szFilterCriteria | Filtering string
// @parm FILTERTYPE | dwFilterType | Filtering type
//
// @retval S_OK success
// @retval E_FAIL failure
// @retval E_INVALIDARG an invalid parameter was passed
// @retval E_OUTOFMEMORY out of memory
//
////////////////////////////////////////////////////////////////
HRESULT CImpIOPCBrowseServer::BrowseFlat(CLongPtrMap *pMap,
long *plNumEntries,
CString szFilterCriteria,
FILTERTYPE dwFilterType)
{
HRESULT hr;
long lTempNumEntries = 0L,
i = 0L,
lKey,
lMapIndex = 0;
int nLength;
CLongPtrMap DevMap,
DBMap;
POSITION posDevMap = NULL,
posDBMap = NULL;
WCHAR *pwcString = NULL,
*pwcEntry = NULL;
CString szDevice,
szDatablock,
szReturnString;
USES_CONVERSION;
switch(m_dwLevel)
{
case DEVICE_LEVEL:
// Get the list of datablocks from the driver
//
hr = GetDeviceList(&DevMap, // Map to store the strings in
&lTempNumEntries, // Number of entries in the map
OPC_BRANCH, // Browse Filter
szFilterCriteria, // String used for filtering
dwFilterType); // Filter type
if (FAILED(hr))
{
FreeMapMemory(&DevMap);
FreeMapMemory(&DBMap);
return E_FAIL;
}
// For each device in the list, get its datablocks
//
posDevMap = DevMap.GetStartPosition();
while (posDevMap != NULL)
{
DevMap.GetNextAssoc(posDevMap, lKey, pwcString);
szDevice = pwcString;
// Get the variables that are leafs
hr = GetDatablockList(&DBMap,
&lTempNumEntries,
szDevice,
OPC_LEAF,
szFilterCriteria,
dwFilterType);
if (FAILED(hr))
{
FreeMapMemory(&DevMap);
FreeMapMemory(&DBMap);
return E_FAIL;
}
// For each datablock in the list, add it to the return map
//
posDBMap = DBMap.GetStartPosition();
while (posDBMap != NULL)
{
DBMap.GetNextAssoc(posDBMap, lKey, pwcString);
szDatablock = pwcString;
// Build up the string to add
szReturnString = szDevice + IOADDRESS_DELIM + szDatablock;
// Allocate the memory and add it to the map
nLength = szReturnString.GetLength();
pwcString = A2W(szReturnString.GetBuffer(nLength+ 1));
szReturnString.ReleaseBuffer();
pwcEntry = new WCHAR [nLength + 1];
if (NULL == pwcEntry)
{
FreeMapMemory(&DevMap);
FreeMapMemory(&DBMap);
return E_OUTOFMEMORY;
}
wcscpy(pwcEntry, pwcString);
pMap->SetAt(lMapIndex, pwcEntry);
lMapIndex++;
}
// Free the map memory so we can use it for the next pass
FreeMapMemory(&DBMap);
}
// Free the map memory so we can use it for the next pass
FreeMapMemory(&DevMap);
break;
case DATABLOCK_LEVEL:
// Get the variables that are leafs
hr = GetDatablockList(&DBMap,
&lTempNumEntries,
m_szDeviceName,
OPC_LEAF,
szFilterCriteria,
dwFilterType);
if (FAILED(hr))
{
FreeMapMemory(&DBMap);
return E_FAIL;
}
// For each datablock in the list, add it to the return map
//
posDBMap = DBMap.GetStartPosition();
while (posDBMap != NULL)
{
DBMap.GetNextAssoc(posDBMap, lKey, pwcString);
szDatablock = pwcString;
// Build up the string to add
szReturnString = m_szDeviceName + IOADDRESS_DELIM + szDatablock;
// Allocate the memory and add it to the map
nLength = szReturnString.GetLength();
pwcString = A2W(szReturnString.GetBuffer(nLength+ 1));
szReturnString.ReleaseBuffer();
pwcEntry = new WCHAR [nLength + 1];
if (NULL == pwcEntry)
{
FreeMapMemory(&DBMap);
return E_OUTOFMEMORY;
}
wcscpy(pwcEntry, pwcString);
pMap->SetAt(lMapIndex, pwcEntry);
lMapIndex++;
}
// Free the map memory so we can use it for the next pass
FreeMapMemory(&DBMap);
break;
default:
// Should never happen!!
TRACE("Invalid Browse Level (%lu), File %s, Line %d\n",
m_dwLevel, __FILE__, __LINE__);
return E_FAIL;
break;
} // END switch(m_dwLevel)
(*plNumEntries) = pMap->GetCount();
return hr;
}
////////////////////////////////////////////////////////////////
// CImpIOPCBrowseServer::GetDeviceList()
//
// @desc This function places all of the devices for a given driver
// in a CMap.
//
// @parm CLongPtrMap * | pMap | Map to store the strings in
// @parm long * | lNumEntries | Number of entries in the map
// @parm OPCBROWSETYPE | dwBrowseType | Browse type (flat or hierarchial)
// @parm CString | szFilterString | Filtering string
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -