目录
1.3 Null Strings and Null Pointers
7 IOPCHDA_SyncAnnotations(可选)接口
10 IOPCHDA_AsyncAnnotations(可选)接口
12 IOPCHDA_DataCallback(客户端接口)接口
本文简单介绍OPC HDA规范的接口的一般信息,以及有关OPC设计者期望如何实现和使用这些接口的一些背景信息。
根据COM规范,客户端必须释放与“out”或“in/out”参数关联的所有内存。这包括由任何结构内的元件指向的存储器。这一点对于客户端编写人员来说非常重要,否则他们将遇到难以找到的内存泄漏。请参阅IDL文件以确定哪些参数是out参数。推荐的方法是客户端创建一个子例程,用于正确释放每种类型的结构。
与成功/失败无关,服务器必须始终为“out”参数返回定义良好的值。释放分配的资源是客户的责任。
注:如果错误结果是任何FAILED错误,如E_OUTOFMEMORY,则OPC HDA服务器应为所有“out”指针返回NULL(这是标准COM行为)。此规则也适用于以下许多函数返回的错误数组(ppErrors)。通常,一个健壮的OPC客户端应该在释放每个“out”或“In/out”指针之前检查其是否为NULL。
根据COM规范,所有方法都必须在每个必需的接口上实现。
根据COM规范,支持的任何可选接口都必须实现该接口中的所有函数,即使该实现只是返回E_NOTIMPL的存根实现。
以下使用这两个术语。它们不是一回事。NULL指针是一个无效的指针(0),如果使用它将导致异常。NULL字符串是指向1个字符数组的有效(非零)指针,其中该字符为NULL(即0)。如果NULL字符串作为[out]参数(或结构的元素)从方法返回,则必须释放该字符串,否则包含NULL的内存将丢失。还要注意,由于COM封送限制,不能为[in,string]参数传递NULL指针。在这种情况下,应传递指向NULL字符串的指针,以指示省略的参数。
您将注意到IDL中的语法size_is(,dwCount)与指向指针的指针结合使用。这表示返回的项是指向指示类型的实际数组的指针,而不是指向指示类型项的指针数组的指针。这简化了服务器和客户端对数据的封送、创建和访问。
客户端从服务器获取数据有两种方式。
1)它可以执行同步读取(简单且相当高效)。这可能适用于读取相对少量数据且不考虑最大效率的相当简单的客户端。以这种方式操作的客户端愿意阻止并等待结果。当请求大量数据时,这可能需要一些时间。这种方法适用于报告或其他非交互式阅读,但对于交互式显示来说非常糟糕。
2)它可以使用异步方法“订阅”数据,异步方法更复杂,但非常高效。这是交互式客户端的推荐行为,因为这将最大限度地减少显示锁定。客户端可以在等待数据返回的同时自由处理其他交互。
OPC规范描述了OPC HDA服务器实现的接口和相应行为,以及OPC客户端应用程序所依赖的接口和行为。OPC特定错误和返回代码的列表包含在本规范的OPC错误代码摘要部分。对于下面描述的每种方法,都包括所有可能的OPC错误代码以及最常见的OLE错误代码的列表。在实践中,客户端可能会遇到额外的错误代码,如RPC和安全相关代码,他们应该做好处理这些代码的准备。
在某些情况下,还允许服务器返回供应商特定的错误代码。这样的代码可以传递给GetErrorString方法。稍后将对此进行更详细的讨论。
在所有情况下,“E”错误代码将指示FAILED类型错误,“S”错误代码至少指示部分成功,最低限度地指示ppErrors数组中有更多信息可用。服务器在返回“S”错误代码时可能返回数据,也可能不返回数据,但如果调用中提供了指向ppErrors数组的指针,则它必须始终返回ppErrors阵列。如果返回给客户端的任何ppErrors代码不是S_OK,则服务器必须返回S_FALSE,以指示客户端应检查ppErrors数组以获取详细信息。
对于所有接口的所有方法,如果从调用返回FAILED代码,则客户端应该认为所有输出值都无效,而服务器应该为所有“out”参数返回NULL指针。这是标准的COM行为。对于异步接口,如果调用返回了FAILED代码,或者返回了S_FALSE,并且单个项的ppErrors代码都是FAILED代码时,将不会进行回调。
通常,客户端在释放每个“out”或“In/out”指针之前,应始终检查其是否为NULL值。
服务器必须提供标准的IUnknown接口。由于这是一个定义良好的接口,因此不进行详细讨论。有关更多信息,请参阅OLE程序员参考资料。必须提供此接口,并按照Microsoft的要求实现所有功能。
IOPCCommon接口是 OPC DA服务器、OPC HDA服务器、OPC AE服务器等服务器共同支持的接口,它提供设置与查询 LocaleID 的能力,通过 LocaleID在组定义时的使用,可以让不同 LCID 的客户应用程序的操作不会相互影响。
1)HRESULT SetLocaleID (dwLcid)
设置此服务器/客户端会话的默认LocaleID。此LocaleID将由此接口上的GetErrorString方法使用。它还应被受LocaleID影响的任何其他服务器函数用作“默认”LocaleID。其他OPC接口可以通过允许通过方法的参数或通过子对象的属性重写此LocaleID来提供额外的LocaleID能力。
2)HRESULT GetLocaleID (pdwLcid)
返回此服务器/客户端会话的默认LocaleID。
3)HRESULT QueryAvailableLocaleIDs (pdwCount, ppdwLcid)
返回此服务器/客户端会话的可用LocaleID。
4)HRESULT GetErrorString(dwError, pszString)
返回服务器特定错误代码的错误字符串。
5)HRESULT SetClientName ( pszName)
允许客户端选择性地向服务器注册客户端名称。
1)HRESULT GetItemAttributes(pdwCount , ppdwAttrID, ppszAttrName, ppszAttrDesc, ppvtAttrDataType)
此函数返回服务器支持的项属性。也支持供应商特定的属性。供应商提供的属性可用于允许客户端访问和显示供应商特定信息。属性数据类型旨在允许在浏览项目ID时进行查询筛选。
2)HRESULT GetAggregates(pdwCount , ppdwAggrID, ppszAggrName, ppszAggrDesc)
此函数返回服务器支持的聚合列表。还支持供应商特定的聚合。供应商提供的聚合是可用的,以允许客户端使用其特定服务器可用的所有功能。如果服务器不支持聚合,则所有指针都为NULL。
3)HRESULT GetHistorianStatus(pwStatus, pftCurrentTime, pftStartTime, pwMajorVersion, pwMinorVersion, pwBuildNumber, pdwMaxReturnValues, ppszStatusString, ppszVendorInfo)
此函数返回有关服务器当前状态的信息。开始时间是可选的,可以作为NULL指针返回。
4)HRESULT GetItemHandles(dwCount, pszItemID, phClient, pphServer, ppErrors)
此函数返回特定HDA项的服务器句柄和客户端句柄之间的关联。
5)HRESULT ReleaseItemHandles(dwCount, phServer, ppErrors)
此函数释放特定HDA项目的服务器句柄和客户端句柄之间的关联。
6)HRESULT ValidateItemIDs(dwCount, pszItemID, ppErrors)
此函数验证服务器是否知道特定的HDA项目ID。
7)HRESULT CreateBrowse(dwCount, pdwAttrID, pOperator, vFilter, pphBrowser, ppErrors)
此函数返回一个指向OPCHDA_BROWSER接口的指针。过滤器将应用于对该浏览器实例的所有方法调用。服务器应验证筛选器阵列。服务器必须支持单个客户端同时访问多个浏览接口。筛选是服务器的可选行为。如果服务器不支持筛选,或者只支持对某些请求的属性进行筛选,则服务器应向浏览器返回一个接口,该接口只对接受的属性进行过滤。不支持过滤的服务器应返回指向未过滤浏览器接口的指针。过滤操作是相加的。若要成功通过筛选条件,项目必须成功满足所有筛选条件。
过滤和浏览的实现是特定于服务器的,但预计具有分层名称空间的服务器可能只对叶应用过滤器,导致它们返回没有满足标准的叶的分支。预计客户端可以创建一个浏览器来定位层次结构的特定区域,使用GetBranchPosition获得完全限定的分支名称,然后将该分支名称传递给使用不同过滤器集的另一个浏览器。
服务器可以选择支持字符串过滤器的通配符。为了表示单个字符,应使用“?”。为了表示多个字符,应使用“*”。
过滤器由三个参数pdwAttrID、pOperator和vFilter定义。如果属性值与筛选器值的关系与筛选器运算符匹配,则筛选器表达式为true。如果给定了多个筛选器表达式,则它们必须全部为true才能包含要包含的项。
1)HRESULT GetEnum(dwBrowseType, ppIEnumString)
此函数根据请求的浏览类型,返回一个指向叶、分支或ItemID列表的IENUM字符串枚举器的指针。分支是否为ItemID尚未确定,可能与服务器有关。枚举集的成员将由浏览器在服务器地址空间中的位置以及创建浏览器接口时过滤器的值来确定。如果没有ItemID通过筛选条件,则枚举集为空。因此,当被要求提供分支列表时,具有平面名称空间的服务器总是会返回一个空枚举器,并且无论被要求提供叶还是ItemID,它都会返回相同的列表,因为根据定义,它的所有项都是叶。
项是可以具有数据值的任何项,并且服务器将为其返回完全限定的ItemID和句柄。树枝和树叶是相互排斥的集合。Leafs始终是Items,如果客户端可以获得其完全限定的ItemID,从而请求并接收其服务器句柄,则分支就是Item。
2)HRESULT ChangeBrowsePosition(dwBrowseDirection, szString)
此函数提供了一种相对于当前位置向上或向下移动的方式,或者直接移动到层次结构中的给定位置。
3)HRESULT GetItemID (szNode, pszItemID)
此功能提供了一种获得完全合格的项目标识的方法。这是必需的,因为浏览函数只返回组成ItemID的组件或令牌,而不返回用于分隔这些令牌的分隔符。
此函数返回从当前浏览位置的GetEnum方法获得的Enum集中的OPCHDA_LEAF或OPCHDA_ItemID的完全限定ItemID。这是一个可以传递给IOPCHDA_Server::GetItemHandles的ID。
4)HRESULT GetBranchPosition (pszBranchPos)
此函数提供层次结构中的当前浏览位置。
从该方法获得的完全限定路径可用于使用OPCHDA_browse_DIRECT标志通过ChangeBrowsePosition方法设置浏览位置。
1)HRESULT ReadRaw (htStartTime, htEndTime, dwNumValues, bBounds, dwNumItems, phServer, ppItemValues, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时域的值、质量和时间戳。当bBounds为TRUE时,将返回时域的边界值。此功能旨在供希望在历史记录中保存实际数据的客户使用。实际数据可以被压缩,或者可以是为项目收集的所有数据,这取决于历史记录和保存项目值时调用的存储规则。提供可选的边界值以允许客户端在对显示器上的实际数据进行趋势分析时对开始和结束时间的值进行插值。
请求的时域由htStartTime、htEndTime和dwNumValues定义;必须至少指定其中两个。如果htEndTime小于htStartTime,或者只指定了htEndTime和dwNumValues,则数据将以相反的顺序返回,后面的数据将先返回。如果指定了这三个值,则调用将根据htStartTime和htEndTime的相对值以升序或降序返回从htStartTime到htEndTime最多dwNumValues的结果。如果dwNumValues为0,则返回该范围内的所有值。OPCHDA_TIME的空值用于指示未指定htStartTime或htEndTime。
如果htStartTime或htEndTime是以字符串(相对)格式给出的,则OPCHDA_time结构的绝对时间(ftTime)应设置为FILETIME,该FILETIME是服务器将相对时间转换为的。
特别允许htStartTime和htEndTime相同。这允许客户端只请求一个值。如果请求的时域超出服务器的范围,则特别不允许服务器返回E_INVALIDARG。这种情况应视为不存在数据的区间。
如果在该时间范围内存在多个dwNumValues结果,则该ItemID的ppErrors条目应为OPC_S_MOREDATA。当返回OPC_S_MOREDATA时,想要下一个dwNumValues值的客户端应再次调用ReadRaw,并将为该项返回的最旧值的时间戳作为新的htStartTime,同时保持htEndTime的原始值不变(如果需要相反的顺序,则反转htStartTime和htEndTime)。请注意,第二次调用将返回上一次调用中最后一个值的副本。
如果请求了边界值,并且指定了非零的dwNumValues,则返回的任何边界值都将包含在dwNumValue计数中。如果dwNumValues为1,则只返回起始边界(如果需要相反的顺序,则返回结束边界)。如果dwNumValues为2,则返回数据点和起始边界(如果需要相反的顺序,则返回结束边界)。
当请求边界值但未找到边界值时,ppItemValues中相应的数组元素的质量将为OPCHDA_NOBOUND,时间戳等于开始或结束时间(视情况而定),VARIANT的值为VT_EMPTY。在历史中查找边界值的前后距离取决于服务器。
如果只指定了htStartTime或htEndTime中的一个,并且指定了非零的dwNumValues,则历史上的最后一个值被视为结束界限(如果需要相反的顺序,则为开始界限)。
对于不存在数据的间隔,如果未请求或未找到边界值,则相应的ppErrors应为OPC_S_NODATA,而OPCHDA_Item的dwCount应为0。如果请求了边界值并且其中一个或两个都存在,则ppError返回为S_OK,并返回边界值。当然,如果任何ppError代码不是S_OK,则返回给客户端的HRESULT必须是S_FALSE。
2)HRESULT ReadProcessed (htStartTime, htEndTime, ftResampleInterval, dwNumItems, phServer, haAggregate, ppItemValues, ppErrors)
该方法可选。
该方法在标准的v1.0和v1.1之间进行了更改,以将haAggregate作为DWORD而非ENUM传递,从而允许供应商指定自己的聚合。使用该标准v1.0构建的服务器和客户端将与使用v1.1构建的服务器或客户端协同工作,但v1.0客户端可能与返回供应商指定聚合的v1.1服务器不兼容。
此函数根据历史数据库中一个或多个项目的指定时域的数据计算聚合值、质量和时间戳。时域被划分为持续时间为ftResampleInterval的子区间。通过使用下一个ftResampleInterval中的数据,为以htStartTime开始的每个子区间计算指定的haAggregate。
此函数旨在提供相对于重采样间隔计算的值。例如,当ftResampleInterval为1小时时,此函数可以为指定时域内的每个项目提供每小时统计信息,如Maximum、Minimum、Average等。
请求的域由htStartTime、htEndTime和htResampleInterval定义。如果htStartTime或htEndTime是以字符串(相对)格式给定的,则返回的值应为服务器将该值转换为的FILETIME。必须指定这三个。如果htEndTime小于htStartTime,则应以相反的顺序返回数据,后面的数据优先。如果htStartTime和htEndTime相同,则服务器应返回E_INVALIDARG,因为没有任何有意义的方法来解释这种情况。
用于计算每个子区间的聚合的值应包括正好落在子区间开始的时间戳上的任何值,但不应包括直接落在子间隔结束的时间戳的任何值。因此,每个值在计算中只能包含一次。如果时域的顺序相反,我们认为较晚的时间戳是子区间的开始时间,较早的时间戳则是子区间结束时间。请注意,这意味着简单地交换开始和结束时间不会导致以相反的顺序返回相同的值,因为在这两种情况下请求的子区间不相同。
如果计算的最后一个子区间不是完整的子区间(请求的时域不能被重新采样间隔整除),则返回的最后一个聚合应基于该不完整的子间隔,并且聚合的质量应为OPCHDA_PARTIAL。
对于MinimumActualTime和MaximumActualTime,如果一个子区间内存在多个值实例,则返回的值实例(时间戳)取决于服务器。在任何情况下,服务器可以设置OPCHDA_EXTRADATA质量标志,以使呼叫者知道存在具有该值的其他时间戳。
要获得同一项目的多个聚合,请在每个所需聚合的项目列表中包含服务器项目句柄。
如果htResampleInterval为0,则服务器应为整个时间范围创建一个聚合值。这允许在长时间内进行聚合。时间戳等于htEndTime的值将从该聚合中排除,就像它将从具有该结束时间的子区间中排除一样。
与聚合一起返回的时间戳应为间隔开始时的时间,除非聚合指定了不同的值。此外,如果聚合所依据的所有值的质量均为良好,则聚合返回的质量应为良好(见OPC数据访问标准)。如果这些值中的任何一个具有任何其他质量,则聚合的质量应为亚正常(0x010110xx)。
如果时域中的任何子区间中不存在给定项的数据,则服务器应在该项的ppErrors数组中返回OPC_S_NODATA,并且相应的ppItemValues结构的dwCount应为0。
如果该项的至少一个子区间中确实存在数据,则服务器应返回时域中每个子区间的时间戳、质量和值。对于没有数据的每个子区间,服务器应返回该子区间的VT_EMPTY值和OPCHDA_NODATA质量,并带有适当的时间戳。如果聚合的时间戳基于数据,则为OPCHDA_NODATA返回的时间戳应为间隔开始的时间戳。
注:供应商定义的聚合在子区间中是否包含后缘值方面可能具有不同的行为。预计服务器供应商将清楚地记录其供应商特定聚合的行为,以便客户端知道每个聚合中包含哪些值。
3)HRESULT ReadAtTime (dwNumTimeStamps, ftTimeStamps, dwNumItems, phServer, ppItemValues, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时间戳的值和质量。此函数旨在提供与具有已知时间戳的其他值相关的值。例如,收集实验室样本时传感器的值。
返回的值和质量的顺序应与请求中提供的时间戳的顺序相匹配。
当指定的时间戳不存在值时,应从周围的值中插入一个值,以表示指定时间戳的值。
OPCHDA_ITEM结构将在haAggregate字段中返回OPCHDA_NOAGGREGATE。
如果找到指定时间戳的值,服务器将在质量中设置OPCHDA_RAW位。如果该值是根据周围的值进行插值的,则服务器将在质量中设置OPCHDA_interpolated位。
4)HRESULT ReadModified(htStartTime, htEndTime, dwNumValues, dwNumItems, phServer, ppItemValues, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时域的修改值、质量、时间戳、用户ID和时间戳。如果ReadRaw、ReadProcessed或ReadAtTime返回的质量为OPCHDA_EXTRADATA,表示存在被取代的值,则此函数将允许您查看被取代的那些值。此函数只读取已修改/替换或删除的值。这是接口上的一个可选方法。
请求的域由htStartTime、htEndTime和dwNumValues定义;必须至少指定其中两个。如果htEndTime小于htStartTime,或者只指定了htEndTime和dwNumValues,则应以相反的顺序返回数据,后面的数据优先。如果指定了这三个值,则调用应根据StartTime和EndTime的相对值以升序或降序返回从StartTime到EndTime的最多dwNumValues结果。如果在该时间范围内存在多个dwNumValues结果,则该ItemID的ppErrors条目应为OPC_S_MOREDATA。如果dwNumValues为0,则返回该范围内的所有值。
如果一个值被修改了多次,则会返回该时间的所有值。这意味着时间戳可以多次出现在数组中。具有相同时间戳的返回值的顺序应该是从最近修改值到最旧修改值。是否保留多次修改或仅保留最近的修改取决于服务器。
5)HRESULT ReadAttribute (htStartTime, htEndTime, hServer, dwNumAttributes, pdwAttributeIDs, ppAttributeValues, ppErrors)
此函数从历史数据库中读取项目指定时域的属性值和时间戳。如果需要属性的当前值,则htStartTime应设置为“NOW”,htEndTime应为NULL。
此函数用于检索已更改的属性,以便将这些属性的值与其数据的值关联起来。例如,传感器的重新校准可能需要改变正常的最大和最小属性。
如果项目唯一可用的属性值是当前值,则应返回这些值,并将ppError设置为OPC_S_CURRENTVALUE。
除了请求当前值(htStartTime=NOW,htEndTime=NULL)的情况外,服务器应始终返回一个起始边界值。因此,如果客户端请求1997年1月1日至1997年10月1日的属性值,则服务器应在1997年1日返回该属性的值,而不是返回的第一个值是1997年1月份1日之后该属性的第一个新值。同样,第一个值的时间戳应为1997年1月1日,而不管属性实际何时取该值。所有其他时间戳应为属性值发生变化的时间。
请注意,虽然客户端可以向服务器查询ItemID的本机数据类型,但客户端不能假设从服务器发送的所有数据都是该数据类型。给定ItemID的数据类型可能在Item的使用寿命内发生了变化,因此客户端应该能够处理接收与此调用返回的数据类型不同的数据类型的数据。
1)HRESULT QueryCapabilities(pCapabilities)
此函数指定服务器支持哪些更新方法。这是所有支持OPCHDA SyncUpdate接口的服务器所必需的方法。
此调用使用ENUM作为返回参数;这对于位掩码值是不正确的,并且排除了服务器指定多个支持的方法。为了避免对此次维护更新的IDL进行更改,对此的更正将推迟到2.0版
2)HRESULT Insert(dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, ppErrors)
此函数在一个或多个项目的指定时间戳将值和质量插入到历史数据库中。如果在指定的时间戳存在值,则不应插入新值;ppErrors应指示错误。这是接口上的一个可选方法。
此函数用于在指定的时间戳插入新值;例如插入实验室数据以反映数据收集的时间。
phServer、ftTimeStamps、vValues和pdwQualities是numItems大小的数组。若要在同一时间插入多个不同项目的值,则ftTimeStamp数组将为每个项目具有相同的时间。要插入单个项目的值、时间戳和质量流,请将项目数组的大小设置为要插入的值的数量,并在每个元素中放置相同的ItemID。
3)HRESULT Replace(dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, ppErrors)
此函数用于替换历史数据库中一个或多个项目在指定时间戳处的值和质量。如果在指定的时间戳处不存在值,则不应插入新值;ppErrors应指示错误。这是接口上的一个可选方法。
此函数用于替换指定时间戳处的现有值;例如,未正确处理但插入历史数据库的正确实验室数据。
phServer、ftTimeStamps、vValues和pdwQualities是numItems大小的数组。若要在同一时间替换多个不同项目的值,则ftTimeStamp数组将为每个项目提供相同的时间。要替换单个项的值、时间戳和质量流,请将项数组的大小设置为要替换的值的数量,并在每个元素中放置相同的ItemID。
4)HRESULT InsertReplace (dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, ppErrors)
此函数在历史数据库中为一个或多个项目插入或替换指定时间戳的值和质量。如果项目在指定的时间戳上有一个值,则新的值和质量将取代旧的值。如果在该时间戳处没有值,则函数将插入新数据。函数在返回之前一直运行到完成。这是接口上的一个可选方法。
此功能旨在无条件地插入/替换值和质量;例如对坏传感器的值的校正。
phServer、ftTimeStamps、vValues和pdwQualities是numItems大小的数组。若要在同一时间设置多个不同项目的值和质量,则ftTimeStamp数组将为每个项目具有相同的时间。要为单个项设置值、时间戳和质量流,请将项数组的大小设置为要插入/替换的值的数量,并在每个元素中放置相同的ItemID。
S_OK作为ppError当HDA服务器无法判断在该时间戳是否已经有值时,允许单个值的返回代码。如果HDA服务器可以确定新值是否替换已经存在的值,则应使用OPC_S_INSERTED或OPC_S_REPLACED返回该信息。
5)HRESULT DeleteRaw (htStartTime, htEndTime, dwNumItems, phServer, ppErrors)
此函数用于从历史数据库中删除组中一个或多个项目的指定时域的值、质量和时间戳。这是接口上的一个可选方法。
此功能用于删除意外输入历史数据库的数据;例如从具有不正确时间戳的源删除数据。
如果在特定项目的时间范围内未找到任何数据,则返回S_FALSE的成功状态,并且该项目的错误代码为OPC_S_NODATA。
6)HRESULT DeleteAtTime (dwNumItems, phServer, ftTimeStamps, ppErrors)
此函数用于删除历史数据库中组中一个或多个项目的指定时间戳的值和质量。这是接口上的一个可选方法。
此功能用于删除历史数据库中的特定数据;例如不正确且不能正确再现的实验室数据。
1)HRESULT QueryCapabilities(pCapabilities)
此函数指定服务器支持哪些更新方法。这是所有支持OPCHDA SyncAnnotations接口的服务器所必需的方法。
此调用使用ENUM作为返回参数;这对于位掩码值是不正确的,并且排除了服务器指定多个支持的方法。为了避免对此次维护更新的IDL进行更改,对此的更正将推迟到2.0版
2)HRESULT Read(htStartTime, htEndTime, dwNumItems, phServer, ppAnnotationValues, ppErrors)
此函数在指定的时间域中从历史数据库中读取指定项目ID的注释。这是所有支持OPCHDA SyncAnnotations接口的服务器所需的方法。
此函数用于在指定的时间戳读取项目的注释。
请求的时域由htStartTime和htEndTime定义。如果htEndTime小于htStartTime,则应以相反的顺序返回数据,后面的数据优先。
仅当时域上不存在注释时,才返回OPC_S_NODATA。
3)HRESULT Insert(dwNumItems, phServer, ftTimeStamps, ppAnnotationValues, ppErrors)
此函数将注释插入到历史数据库中,以记录指定时间戳的值的观察结果。这是接口上的一个可选方法。
异步操作允许客户端向服务器发送请求,而无需等待服务器填写请求并返回数据。每个操作都有一个关联的事务ID(由客户端创建),该ID在回调到客户端期间与数据一起返回。OPC HDA服务器的异步方法是使用IConnectionPoint实现的。这允许客户端建立不同的回调来处理不同类型的数据传输。虽然本文档后面提供了一些关于IConnectionPoint的信息,但建议阅读Microsoft文档。
预计某些服务器将不支持此处指定的所有异步接口。但是,所有服务器都必须支持IConnectPointContainer,并且任何支持任何异步接口的服务器都必须支撑IOPCHDA_DataCallback ConnectionPoint。如果服务器不支持特定接口,则无需实现向客户端的IOPCHDA_Data_callback对象中的匹配回调例程发送回调的方法。
如果需要,客户端提供一个TransactionID来区分一个调用和另一个调用。由于对异步调用的响应实际上可以在调用完成之前到达,因此客户端应该在进行调用之前存储此TransactionID,这样回调例程就可以访问TransactionID。相反,CancelID由服务器生成,如果客户端希望取消异步请求,则用于取消异步请求。
1)HRESULT ReadRaw (dwTransactionID, htStartTime, htEndTime, dwNumValues, bBounds, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时域的值、质量和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnReadComplete方法返回。
当bBounds为TRUE时,将返回时域的边界值。此功能旨在供希望在历史记录中保存实际数据的客户使用。实际数据可以被压缩,或者可以是为项目收集的所有数据,这取决于历史记录和保存项目值时调用的存储规则。提供可选的边界值以允许客户端在对显示器上的实际数据进行趋势分析时对开始和结束时间的值进行插值。
2)HRESULT AdviseRaw(dwTransactionID, htStartTime, ftUpdateInterval, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数在一个或多个项目的更新间隔从指定的开始时间读取历史数据库中的值、质量和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnDataChange方法返回。这是接口上的一个可选方法。
请求的时域由htStartTime和htEndTime定义。如果htEndTime小于htStartTime,则应以相反的顺序返回数据,后面的数据优先。与同步方法不同的是,如果dwNumValues为非零,则函数将继续以dwNumValue大小的块发送数据,直到发送完所有请求的数据为止。CancelID可用于取消请求。
回调应包含请求中所有ItemID的数据,但返回FAILED错误代码的ItemID除外。
请参阅IOPCHDA_SyncRead:ReadRaw上的讨论,了解服务器在各种情况下应向客户端返回的内容。
3)HRESULT ReadProcessed (dwTransactionID, htStartTime, htEndTime, ftResampleInterval, dwNumItems, phServer, haAggregate, pdwCancelID, ppErrors)
此函数根据历史数据库中一个或多个项目的指定时域的数据计算聚合值、质量和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnReadComplete方法返回。这是接口上的一个可选方法。
此功能用于在客户端软件可用时使用新数据更新客户端软件;例如周期性地用新数据更新趋势。
该请求将针对从htStartTime到未来的所有数据,因为它是以ftUpdateInterval指定的速率收集和报告的。报告将继续,直到请求被取消。在指定当前之前的开始时间时应注意,因为已经可用的数据将被无限制地返回,每个响应中都有相当于ftUpdateInterval的数据。一旦发送了所有已经收集的数据,就会为每个ftUpdateInterval发送新的数据。
如果没有新数据,服务器仍应发送一个响应,其中每个项目都有一个条目,对于没有数据的任何项目,dwCount为零,ppErrors代码为OPC_S_NODATA。通过这种方式,客户端可以确保间隔已被处理。
此函数使用ftUpdateInterval来限制数据返回率。
通知中不会标识任何注释。
请参阅IOPCHDA_SyncRead:ReadRaw上的讨论,了解服务器在各种情况下应向客户端返回的内容。
4)HRESULT AdviseProcessed (dwTransactionID, htStartTime, ftResampleInterval, dwNumItems, phServer, haAggregate, dwNumIntervals, pdwCancelID, ppErrors)
该方法在标准的v1.0和v1.1之间进行了更改,以将haAggregate作为DWORD而非ENUM传递,从而允许供应商指定自己的聚合。使用该标准v1.0构建的服务器和客户端将与使用v1.1构建的服务器或客户端协同工作,但v1.0客户端可能与返回供应商指定聚合的v1.1服务器不兼容。
此函数从一个或多个项目的指定开始时间间隔计算历史数据库中的聚合值、质量和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnDataChange方法返回。这是接口上的一个可选方法。
此函数根据历史数据库中一个或多个项目的指定时域的数据计算聚合值、质量和时间戳。时域被划分为持续时间为ftResampleInterval的子区间。通过使用下一个ftResampleInterval中的数据,为以htStartTime开始的每个子区间计算指定的haAggregate。
此函数旨在提供相对于重采样间隔计算的值。例如,当ftResampleInterval为1小时时,此函数可以为指定时域内的每个项目提供每小时统计信息,如Maximum、Minimum、Average等。
请求的域由htStartTime、htEndTime和htResampleInterval定义。如果htStartTime或htEndTime是以字符串(相对)格式给定的,则返回的值应为服务器将该值转换为的FILETIME。必须指定这三个。如果htEndTime小于htStartTime,则应以相反的顺序返回数据,后面的数据优先。
对于MinimumActualTime和MaximumActualTime,如果一个子区间内存在多个值实例,则返回的值实例(时间戳)取决于服务器。在任何情况下,服务器可以设置OPCHDA_EXTRADATA质量标志,以使呼叫者知道存在具有该值的其他时间戳。
如果htResampleInterval为0,则服务器应为整个时间范围创建一个聚合值。这允许在长时间内进行聚合。
请参阅IOPCHDA_SyncRead:ReadProcessed上的讨论,了解服务器在各种情况下应向客户端返回的内容。
5)HRESULT ReadAtTime (dwTransactionID, dwNumTimeStamps, ftTimeStamps, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时间戳的值和质量。此函数旨在提供与具有已知时间戳的其他值相关的值。例如,收集实验室样本时传感器的值。结果通过客户端的IOPCHDA_DataCallback::OnReadComplete方法返回。这是接口上的一个可选方法。
当指定的时间戳不存在值时,应从周围的值中插入一个值,以表示指定时间戳的值。
OPCHDA_ITEM结构将在haAggregate字段中返回OPCHDA_NOAGGREGATE。
如果找到指定时间戳的值,服务器将以质量返回OPCHDA_RAW。如果该值是根据周围的值进行插值的,则服务器将以质量返回OPCHDA_interpolated。
6)HRESULT ReadModified (dwTransactionID, htStartTime, htEndTime, dwNumValues, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数从历史数据库中读取一个或多个项目的指定时域的值、质量、时间戳、用户ID和修改时间戳。结果通过客户端的IOPCHDA_DataCallback::OnReadModifiedComplete方法返回。此功能的目的是读取已修改/替换的历史记录中的值。如果ReadRaw、ReadProcessed或ReadAtTime返回的质量为OPCHDA_EXTRADATA,表示存在被取代的值,则此函数将允许您查看被取代的那些值。此函数只读取已修改/替换或删除的值。这是接口上的一个可选方法。
7)HRESULT ReadAttribute (dwTransactionID, htStartTime, htEndTime, hServer, dwNumAttributes, dwAttributeIDs, pdwCancelID, ppErrors)
此函数从历史数据库中读取项目指定时域的属性值和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnReadAttributeComplete方法返回。这是接口上的一个可选方法。
此函数从历史数据库中读取一个或多个项目的指定时域的修改值、质量、时间戳、用户ID和时间戳。
此函数的目的是读取已修改/替换的历史记录中的值(返回的值的质量为OPCHDA_EXTRADATA,表示该项/时间戳还有其他已被替换的值)。
请求的时域由htStartTime和htEndTime定义。如果htEndTime小于htStartTime,则应以相反的顺序返回数据,后面的数据优先。与同步方法不同的是,如果dwNumValues为非零,则函数将继续以dwNumValue大小的块发送数据,直到发送完所有请求的数据为止。CancelID可用于取消请求。
如果一个值被修改了多次,则会返回该时间的所有值。这意味着时间戳可以多次出现在数组中。具有相同时间戳的返回值的顺序应该是从最近修改值到最旧修改值。它是保留多次修改还是只保留最近的修改,这取决于服务器。
在异步ReadModified中,与同步不同,如果指定了所有三个参数(htStartTime、htEndTime和dwNumValues),则函数将继续以dwNumValue大小的块发送数据,直到发送完所有请求的数据。可用于取消请求的CancelID。
8)HRESULT Cancel(dwCancelID)
此功能取消未完成的操作。实际实现是特定于服务器的,但服务器将通过客户端的IOPCHDA_Data_Callback::OnCancelComplete方法进行响应,除非调用返回FAILED错误代码。
此函数从历史数据库中读取项目指定时域的属性值和时间戳。
此调用使用ENUM作为返回参数;这对于位掩码值是不正确的,并且排除了服务器指定多个支持的方法。为了避免对此次维护更新的IDL进行更改,对此的更正将推迟到2.0版。
1)HRESULT QueryCapabilities(pCapabilities)
此函数指定服务器支持哪些更新方法。它是所有支持OPCHDA AsyncUpdate接口的服务器所必需的方法。
2)HRESULT Insert(dwTransactionID, dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, pdwCancelID, ppErrors)
此函数将一个或多个项目的指定时间戳的值和质量插入到历史数据库中。结果通过客户端的IOPCHDA_DataCallback::OnUpdateComplete方法返回。这是接口上的一个可选方法。
3)HRESULT Replace (dwTransactionID, dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, pdwCancelID, ppErrors)
此函数用于替换历史数据库中一个或多个项目在指定时间戳处的值和质量。结果通过客户端的IOPCHDA_DataCallback::OnUpdateComplete方法返回。这是接口上的一个可选方法。
4)HRESULT InsertReplace(dwTransactionID, dwNumItems, phServer, ftTimeStamps, vDataValues, pdwQualities, pdwCancelID, ppErrors)
此函数在一个或多个项目的指定时间戳插入或替换值和质量。如果项目在指定的时间戳上有一个值,则新的值和质量将取代旧的值。如果在该时间戳处没有值,则函数将插入新数据。结果通过客户端的IOPCHDA_DataCallback::OnUpdateComplete方法返回。这是接口上的一个可选方法。
5)HRESULT DeleteRaw (dwTransactionID, htStartTime, htEndTime, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数用于从历史数据库中删除一个或多个项目的指定时域的值、质量和时间戳。结果通过客户端的IOPCHDA_DataCallback::OnUpdateComplete方法返回。这是接口上的一个可选方法。
6)HRESULT DeleteAtTime (dwTransactionID, dwNumItems, phServer, ftTimeStamps, pdwCancelID, ppErrors)
此函数用于删除历史数据库中一个或多个项目的指定时间戳的值和质量。结果通过客户端的IOPCHDA_DataCallback::OnUpdateComplete方法返回。这是接口上的一个可选方法。
7)HRESULT Cancel(dwCancelID)
此功能取消未完成的操作。实际实现是特定于服务器的,但服务器将通过客户端的IOPCHDA_Data_Callback::OnCancelComplete方法进行响应,除非调用返回FAILED错误代码。
1)HRESULT QueryCapabilities(pCapabilities)
此函数指定服务器支持的注释方法。它是所有支持OPCHDA AsyncAnnotations接口的服务器所必需的方法。
2)HRESULT Read(dwTransactionID, htStartTime, htEndTime, dwNumItems, phServer, pdwCancelID, ppErrors)
此函数在指定的时间域中从历史数据库中读取指定项目ID的注释。此函数用于读取用户输入的注释,以记录指定时间戳下某个值的观测结果。结果通过客户端的IOPCHDA_DataCallback::OnReadAnnotations方法返回。
3)HRESULT Insert(dwTransactionID, dwNumItems, phServer, ftTimeStamps, pAnnotationValues, pdwCancelID, ppErrors)
此函数将注释插入到历史数据库中。此函数用于由用户插入注释,以记录指定时间戳的值的观察结果。结果通过客户端的IOPCHDA_DataCallback::OnInsertAnnotations方法返回。这是接口上的一个可选方法。
4)HRESULT Cancel(dwCancelID)
此功能取消未完成的操作。实际实现是特定于服务器的,但服务器应通过客户端的IOPCHDA_DataCallback::OnCancelComplete方法进行响应,除非调用返回FAILED错误代码。
此接口支持历史服务器的播放功能。这提供了从历史服务器获得初始数据集的能力,然后获得历史数据的持续更新。这与异步建议方法的不同之处在于,这些方法以当前时间为中心。回放接口支持从过去检索数据,然后从存储的数据中提供更新的方法。通常,更新以比数据存储时更频繁的速率发送。例如,请求可以是每分钟发送10分钟的数据。
1)HRESULT ReadRawWithUpdate(dwTransactionID, htStartTime, htEndTime, dwNumValues, ftUpdateDuration, ftUpdateInterval, dwNumItems, phServer, pdwCancelID, ppErrors)
此操作最初将检索从开始时间到结束时间的数据。在初始响应之后,它将定期(以ftUpdateInterval)响应由ftUpdateDuration标识的数据量。初始响应的结束时间用作第一次更新的开始时间。之后,上次更新的结束时间被用作下一次更新的开始时间。
此功能用于播放原始历史数据。通过控制更新间隔,数据可以实时、慢速或比实时更快地显示在趋势上。
结果通过客户端的IOPCHDA_DataCallback::OnPlayback方法返回。
仅支持向前播放。初始请求的域由htStartTime、htEndTime和dwNumValues定义。必须定义htStartTime的值。如果未指定htEndTime,则该请求应针对htStartTime中所请求值数的所有数据。然后,应根据上次返回值时的ftUpdateDuration和ftUpdateInterval发送进一步的数据。
如果htStartTime或htEndTime是以字符串(相对)格式给定的,则OPCHDA_time结构(ftTime)的绝对时间将设置为服务器将相对时间转换为的FILETIME。
该请求继续以dwNumvals的块发送数据,直到所有请求的数据都已发送,返回可用于取消请求的事务ID,并使用组上的更新率来限制块返回率。
dwNumValues定义了将在单个回调中返回的任何项的最大值数。这可能是针对初始数据集或任何后续更新(因此请注意,更新可能需要多个回调)。
操作的实现取决于服务器。
2)HRESULT ReadProcessedWithUpdate(dwTransactionID, htStartTime, htEndTime, ftResampleInterval, dwNumIntervals, ftUpdateInterval, dwNumItems, phServer, haAggregate, pdwCancelID, ppErrors)
该方法在标准的v1.0和v1.1之间进行了更改,以将haAggregate作为DWORD而非ENUM传递,从而允许供应商指定自己的聚合。使用该标准v1.0构建的服务器和客户端将与使用v1.1构建的服务器或客户端协同工作,但v1.0客户端可能与返回供应商指定聚合的v1.1服务器不兼容。
此操作最初将检索从开始时间到结束时间的数据。在初始响应之后,它将周期性地(以ftUpdateInterval)响应dwNumIntervals数量的数据,这些数据被划分为ftResampleInterval大小的仓。初始响应的结束时间用作第一次更新的开始时间。之后,上次更新的结束时间被用作下一次更新的开始时间。这是接口上的一个可选方法。
此功能用于播放处理过的历史数据。通过控制更新间隔,数据可以实时、慢速或比实时更快地显示在趋势上。
结果通过客户端的IOPCHDA_DataCallback::OnPlayback方法返回。
初始请求的域由htStartTime、htEndTime和ftResampleInterval定义。如果htStartTime或htEndTime是以字符串(相对)格式给定的,则返回的值将是服务器将该值转换为的FILETIME。必须指定这三个。htEndTime必须大于htStartTime。
ftResampleInterval确定将整个间隔划分为多少个子间隔。指定的函数在以htStartTime开始的每个子区间计算,并选择下一个ftResampleInterval内的数据,将根据每个子区间的haAggregate计算一个值。
对于与聚合值一起使用的MinimumActualTime和MaximumActualTime,如果在一个时间范围内存在该值的多个实例,则返回该值的哪个实例(时间戳)取决于服务器。在任何情况下,服务器可以设置OPCHDA_EXTRADATA质量标志,以使呼叫者知道存在具有该值的其他时间戳。
更新的域由上次返回值的时间ftResampleInterval和dwNumIntervals定义。
ftResampleInterval为0是非法的,导致返回状态为E_INVALIDARG。如果只需要初始数据集,则dwNumIntervals应设置为0。请求仍必须取消。
FTUpdateInterval不能小于FTResampleInterval。
返回的数据的顺序将与请求中ItemID的顺序相匹配。
3)HRESULT Cancel(dwCancelID)
此功能取消未完成的操作。实际实现是特定于服务器的,但服务器将通过OPCHDA_CancelComplete回调进行响应,除非调用返回FAILED错误代码。
1)HRESULT OnDataChange(dwTransactionID, hrStatus, dwNumItems, pItemValues, phrErrors)
此方法由客户端提供,用于处理来自OPCHDA服务器的通知,这些通知是由对OPCHDA_AsyncRead::AdviseRaw和OPCHDA_AsyncRead::AdviseProcessed的调用引起的。
请注意,无论phrErrors字段的内容如何,都必须定义好项值。
2)HRESULT OnReadComplete(dwTransactionID, hrStatus, dwNumItems, pItemValues, phrErrors)
此方法由客户端提供,用于处理从OPCHDA_AsyncRead::ReadRaw、OPCHDA_AsyncRead::ReadProcessed和OPCHDA-AsyncRead:ReadAtTime返回的数据。
请注意,无论phrErrors字段的内容如何,都必须定义好项值。这意味着pItemValues数组将存在,并且将具有dwNumItems成员。如果phrErrors字段指示成员没有数据,则pItemValues条目的dwCount将为0,时间戳、质量和数据的指针为NULL。客户端句柄和AggregateID必须仍然有效。
请注意,给定的客户端句柄、聚合类型或时间戳可能在数组中出现多次。
3)HRESULT OnReadModifiedComplete (dwTransactionID, hrStatus, dwNumItems, pItemValues, phrErrors)
此方法由客户端提供,用于处理从OPCHDA_AsyncRead::ReadModified返回的数据。
请注意,无论phrErrors字段的内容如何,都必须定义好项值。
还要注意,给定的客户端句柄或时间戳可能在数组中出现多次。
4)HRESULT OnReadAttributeComplete(dwTransactionID, hrStatus, hClient, dwNumItems, pAttributeValues, phrErrors)
此方法由客户端提供,用于处理从OPCHDA_AsyncRead::ReadAttribute返回的数据。
请注意,无论phrErrors字段的内容如何,都必须定义好属性值。
请注意,无论phrErrors字段的内容如何,都必须定义好注释值。
5)HRESULT OnReadAnnotations(dwTransactionID, hrStatus, dwNumItems, pAnnotationValues, phrErrors)
此方法由客户端提供,用于处理从OPCHDA_AsyncReadAnnotations::Read返回的数据。
6)HRESULT OnInsertAnnotations (dwTransactionID, hrStatus, dwCount, phClients, phrErrors)
此方法由客户端提供,用于在完成OPCHDA_AsyncAnnotations::Insert时处理来自服务器的通知。
请注意,在初始请求中返回错误的项目不应在此处返回,即返回的列表可能是“稀疏的”,并且没有指定其顺序。
7)HRESULT OnPlayback (dwTransactionID, hrStatus, dwNumItems, ppItemValues, phrErrors)
此方法由客户端提供,用于处理来自OPCHDA服务器的通知,这些通知是由对OPCHDA_Playback::ReadRawWithUpdate和OPCHDA_Playback::ReadProcessedWithUpdate的调用引起的。
请注意,无论phrErrors字段的内容如何,都必须定义好值、时间戳和质量。
8)HRESULT OnUpdateComplete (dwTransactionID, hrStatus, dwCount, phClients, phrErrors)
此方法由客户端提供,用于在完成OPCHDA_AsyncUpdate::Insert、OPCHDA_AsyncUpdate::Replace、OPCHDA_AsyncUpdate::InsertReplace、OPCHDA_AsyncUpdate::DeleteRaw和OPCHDA-AsyncUpdate:::DeleteAtTime时处理来自服务器的通知。
请注意,在初始请求中返回错误的项目不应在此处返回。即,返回的列表可能是“稀疏的”。但是,返回列表的顺序必须与更新调用的参数顺序相匹配,以允许客户端将phrErrors代码与请求的实际更新相匹配。这是必要的,因为客户端可能在一次调用中对同一项应用多个更新,而知道哪些更新没有成功的唯一方法是按照phrErrors数组的顺序。
9)HRESULT OnCancelComplete(dwCancelID)
此方法由客户端提供,用于在异步取消完成时处理来自服务器的通知。
此回调仅在异步取消之后发生。请注意,如果Cancel Request返回S_OK,则客户端可能会收到此回调。如果取消请求失败,则客户端不应收到此回调。