The WinTECH Software Rapid Development DLL for HDA Servers, (WtHDAsvr), provides an easy to use API for integrating custom data with OPC. All the details of COM and OPC are handled by the DLL, which allows an application to present data to OPC at a high-level, without having to be concerned with the actual implementation of the underlying interfaces. The DLL may be easily integrated with existing applications, or new ones.
WtHDAsvr basically operates as a logical wrapper containing support for all the OPC Historical Data Access Interfaces. The controlling application is responsible for defining the item names, attributes and aggregate values that it has available and the dll handles all the actual COM/DCOM Interface calls. As various HDA Clients connect and request historical data, the dll calls back into the application to satisfy the request. The callback mechanism used by the WtHDAsvr dll consists of a C++ object with overloaded functions to read timestamps, item values, attributes and calculations. These function definitions which must be supplied by the application are designed to be easy to implement and of the four, only the timestamp and item value functions are required. Support for Attribute and Agregate values is optional.
The first step in creating an OPC Server is to obtain and install the OPC Proxy/Stub DLL’s from OPCFoundation. Theses are available from the OPC Foundation's public download web page located at: (http://www.opcfoundation.org). Just follow the links through "Technical Information", "Common Downloads for Programmers".
As of Feb. 10, 2001, the link from the OPC Foundation site for the hda proxy dll contains the wrong dll. The opchda_ps.dll required for a HDA server implementation is contained in the wthdasvr.zip file. If you have trouble finding any of the required dll's, please contact us at opc@win-tech.com.
WtHDAsvr.lib contains the export definitions for the DLL’s API. Include this file with the project files for the custom application and include WtHDAsvrAPI.h with those modules which will be making calls into the DLL.
Each OPC Server is identified by a unique CLSID. The GUIDGen.exe utility supplied by Microsoft may be used to generate a unique identifier for the new server application. Run GUIDGen.exe, (located in the Visual C++\Bin directory). Generate a new CLSID and copy to the clipboard to be pasted in to your server application as described below.
The WtHDAsvr.DLL exports two API functions that make modifications to the Windows Registry for installation of the custom server.
HDAUpdateRegistry (GUID CLSID_Svr, LPCSTR Name, LPCSTR Descr, LPCSTR ExePath);
UnregisterHDAServer (GUID CLSID_Svr, LPCSTR Name);
These functions take as arguments the CLSID generated above, (as well as text strings to identify and describe the new server). While the HDAUpdateRegistry and UnregisterHDAServer functions may be called from the controlling application at any time, it is generally preferred to implement the registry functions based on command-line entries during start-up of the application. A self-registering server would process the \RegServer and \UnregServer command line options similar to the code below, (extracted from HDASimSvr Application):
const GUID CLSID_HDASimSvr = {0x99b8f471, 0xc027, 0x11d2, {0x80, 0xb8, 0x0, 0x60, 0x97, 0x58, 0x58, 0xbe}}; BOOL CHDASimSvrApp::InitInstance() { TCHAR szTokens[] = _T("-/ "); CString HelpPath; CString SvrName, SvrDescrip; int i; HelpPath = AfxGetApp()->m_pszHelpFilePath; i = HelpPath.ReverseFind('\\'); HelpPath = HelpPath.Left(i+1); HelpPath += "HDASIMSVR.EXE"; // // Self-Registration code // (look for cmdline options to register & unregister server) // SvrName = "WinTECH.HDAServer"; SvrDescrip = "WinTECH Software OPC HIstorical Data Access Server Simulator"; CString tempCmdLine(m_lpCmdLine); LPTSTR lpszToken = _tcstok(tempCmdLine.GetBuffer(1), szTokens); while (lpszToken != NULL) { if (_tcsicmp(lpszToken, _T("UnregServer"))==0) { UnregisterHDAServer(CLSID_HDASimSvr, SvrName); return (FALSE); } else if (_tcsicmp(lpszToken, _T("RegServer"))==0) { UpdateRegistry (CLSID_HDASimSvr, SvrName, SvrDescrip, HelpPath); return (FALSE); } lpszToken = _tcstok(NULL, szTokens); }
The Windows Registration functions described above may be called prior to the initialization of the WtHDAsvr.DLL. During the self-registration process, the focus is on making the necessary changes to the Registry and then exiting the application. There is no need at this point to go through the effort of initializing DCOM and loading up the OPC Server support. The exported function:
InitWtHDAsvr (GUID CLSID_Svr, UINT ServerRate);
does just that. When this function is executed, the DLL performs all necessary initialization of COM/DCOM and creates the HDAServer Interface object to be used for client connections. The specified ServerRate defines how fast the dll responds to asyncronous read requests from an attached HDA Client.
After initialization, the WtHDAsvr.DLL is now ready to accept connections from prospective clients. The application must define the items that are to be made available:
DefineHDAItem (LPCSTR Name);
As each item reference is made, the dll returns an identifying handle that will be used as an argument in the callback procedures. The application must save this handle to cross reference with the item on read data requests.
If the server application supports additional item attributes or calculations, these must also be defined:
DefineHDAAttribute (DWORD Id, LPCSTR Name, LPCSTR Descr, VARTYPE vt, BOOL IsArchived);
DefineHDAAggregate (DWORD Id, LPCSTR Name, LPCSTR Descr);
Defining the item names, attributes and aggregates supplies the dll with enough information to satisfy browsing requests from an attached client. If a client requests data from the application, however, the dll needs a way to call back into the controlling application to satisfy the request. This is accomplished by using an exported C++ Object with read functions that may be overloaded by the application. (For a detailed description and example code, please refer to the HDATest1 example application that is included with the toolkit.)
GetTimeStamps (HANDLE hItem, FILETIME *pStart, FILETIME *pEnd, int NumValues, FILETIME *pTimes);
This function allows the dll to obtain a list of timestamps that are available for a given item between the specified start and end times. These time values are then used by the dll to read item values from the applications's database.
ReadAt (HANDLE hItem, FILETIME TimeStamp, VARIANT *pValue, DWORD *pQuality);
If the server chooses to support attributes and aggregates, it must also overload the following functions in the callback object:
ReadCurrentAttribute (HANDLE hItem, DWORD AttributeID, FILETIME *pTime,
VARIANT *pValue);
ReadAttributeAt (HANDLE hItem, DWORD AttributeID, FILETIME TimeStamp,
VARIANT *pValue);
ReadProcessed (HANDLE hItem, DWORD AggregateID, FILETIME *pStart,
FILETIME *pEnd, VARIANT *pValue, DWORD *pQuality);
Last Updated: Feb 13, 2006