/// <summary>
        /// Insert annotations.
        /// </summary>
        private StatusCode InsertAnnotations(
            HdaItem item,
            DataValueCollection values,
            out int[] errors)
        {
            errors = null;
            string methodName = "IOPCHDA_SyncAnnotations.Insert";

            int dwNumItems = values.Count;
            int[] phServer = new int[dwNumItems];
            System.Runtime.InteropServices.ComTypes.FILETIME[] ftTimeStamps = new System.Runtime.InteropServices.ComTypes.FILETIME[dwNumItems];
            OPCHDA_ANNOTATION[] pAnnotationValues = new OPCHDA_ANNOTATION[dwNumItems];

            IntPtr ppErrors;

            try
            {
                for (int ii = 0; ii < dwNumItems; ii++)
                {
                    DataValue value = values[ii];

                    phServer[ii] = item.ServerHandle;
                    ftTimeStamps[ii] = ComUtils.GetFILETIME(value.SourceTimestamp);
                    pAnnotationValues[ii] = new OPCHDA_ANNOTATION();

                    // pass an empty structure if the annotation is not valid.
                    pAnnotationValues[ii].dwNumValues = 0;

                    Annotation annotation = value.GetValue<Annotation>(null);

                    if (annotation != null && !String.IsNullOrEmpty(annotation.Message))
                    {
                        pAnnotationValues[ii].dwNumValues = 1;
                        pAnnotationValues[ii].ftAnnotationTime = ComUtils.GetFILETIMEs(new DateTime[] { annotation.AnnotationTime });
                        pAnnotationValues[ii].ftTimeStamps = ComUtils.GetFILETIMEs(new DateTime[] { value.SourceTimestamp });
                        pAnnotationValues[ii].szAnnotation = ComUtils.GetUnicodeStrings(new string[] { annotation.Message });
                        pAnnotationValues[ii].szUser = ComUtils.GetUnicodeStrings(new string[] { annotation.UserName });
                    }
                }

                IOPCHDA_SyncAnnotations server = BeginComCall<IOPCHDA_SyncAnnotations>(methodName, true);

                server.Insert(
                    dwNumItems,
                    phServer,
                    ftTimeStamps,
                    pAnnotationValues,
                    out ppErrors);

                // check for error.
                errors = ComUtils.GetInt32s(ref ppErrors, dwNumItems, true);
                
                // set bad type error for invalid annotations.
                for (int ii = 0; ii < dwNumItems; ii++)
                {
                    if (pAnnotationValues[ii].dwNumValues == 0)
                    {
                        errors[ii] = ResultIds.E_BADTYPE;
                    }
                }
            }
            catch (Exception e)
            {
                ComCallError(methodName, e);
                return StatusCodes.BadUnexpectedError;
            }
            finally
            {
                EndComCall(methodName);

                // free allocated memory.
                for (int ii = 0; ii < dwNumItems; ii++)
                {
                    if (pAnnotationValues[ii].dwNumValues == 0)
                    {
                        continue;
                    }

                    IntPtr[] pointers = new IntPtr[1];
                    Marshal.Copy(pAnnotationValues[ii].szUser, pointers, 0, 1);
                    Marshal.FreeCoTaskMem(pointers[0]);

                    Marshal.Copy(pAnnotationValues[ii].szAnnotation, pointers, 0, 1);
                    Marshal.FreeCoTaskMem(pointers[0]);

                    Marshal.FreeCoTaskMem(pAnnotationValues[ii].ftAnnotationTime);
                    Marshal.FreeCoTaskMem(pAnnotationValues[ii].ftTimeStamps);
                    Marshal.FreeCoTaskMem(pAnnotationValues[ii].szUser);
                    Marshal.FreeCoTaskMem(pAnnotationValues[ii].szAnnotation);
                }
            }

            return StatusCodes.Good;
        }
 /// <summary>
 /// Called when an async read annotations completes.
 /// </summary>
 public  void OnReadAnnotations(
     int dwTransactionID, 
     int hrStatus,
     int dwNumItems, 
     OPCHDA_ANNOTATION[] pAnnotationValues,
     int[] phrErrors)
 {
     try
     {
         // TBD
     }
     catch (Exception e)
     {
         Utils.Trace(e, "Unexpected error processing OnReadAnnotations callback.");
     }
 }