/// <summary> /// Utility to set a string property on an INativeContactProperties. /// </summary> /// <param name="contact">The INativeContactProperties to set the value on.</param> /// <param name="propertyName">The property to set.</param> /// <param name="value">The value to set to the property.</param> /// <returns>HRESULT.</returns> /// <remarks> /// This is a thin wrapper over the COM INativeContactProperties::SetString to make it more easily consumable /// in .Net. Behavior and returned error codes should be similar to the native version. /// </remarks> public static HRESULT SetString(INativeContactProperties contact, string propertyName, string value) { Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); return contact.SetString(propertyName, ContactValue.CGD_DEFAULT, value); }
/// <summary> /// Utility to set a date property on an INativeContactProperties. /// </summary> /// <param name="contact">The INativeContactProperties to set the value on.</param> /// <param name="propertyName">The property to set.</param> /// <param name="value">The date value to set to the property.</param> /// <returns>HRESULT.</returns> /// <remarks> /// This is a thin wrapper over the COM INativeContactProperties::SetDate to make it more easily consumable /// in .Net. Behavior and returned error codes should be similar to the native version. /// </remarks> public static HRESULT SetDate(INativeContactProperties contact, string propertyName, DateTime value) { Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); // If the caller hasn't explicitly set the kind then assume it's UTC // so it will be written as read to the Contact. if (value.Kind != DateTimeKind.Local) { value = new DateTime(value.Ticks, DateTimeKind.Utc); } long longFiletime = value.ToFileTime(); var ft = new FILETIME { dwLowDateTime = (Int32)longFiletime, dwHighDateTime = (Int32)(longFiletime >> 32) }; return contact.SetDate(propertyName, ContactValue.CGD_DEFAULT, ft); }
/// <summary> /// Utility to augment the label set on a preexisting array node in an INativeContactProperties. /// </summary> /// <param name="contact">The INativeContactProperties where the labels are to be set.</param> /// <param name="arrayNode">The array node to apply the labels to.</param> /// <param name="labels">The labels to add to the array node.</param> /// <returns>HRESULT.</returns> /// <remarks> /// This is a thin wrapper over the COM INativeContactProperties::SetLabels to make it more easily consumable /// in .Net. Behavior and returned error codes should be similar to the native version. /// </remarks> public static HRESULT SetLabels(INativeContactProperties contact, string arrayNode, ICollection<string> labels) { Verify.IsNotNull(contact, "contact"); using (var marshalable = new MarshalableLabelCollection(labels)) { return contact.SetLabels(arrayNode, ContactValue.CGD_DEFAULT, marshalable.Count, marshalable.MarshaledLabels); } }
public static HRESULT GetString(INativeContactProperties contact, string propertyName, bool ignoreDeletes, out string value) { value = null; Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); uint cch; var sb = new StringBuilder((int)Win32Value.MAX_PATH); HRESULT hr = contact.GetString(propertyName, ContactValue.CGD_DEFAULT, sb, (uint)sb.Capacity, out cch); // If the caller doesn't care about deleted properties, convert the error code. if (ignoreDeletes && HRESULT.S_FALSE == hr) { hr = Win32Error.ERROR_PATH_NOT_FOUND; } // If we didn't have enough space for the value the first time through, try the bigger size. if (Win32Error.ERROR_INSUFFICIENT_BUFFER == hr) { sb.EnsureCapacity((int)cch); hr = contact.GetString(propertyName, ContactValue.CGD_DEFAULT, sb, (uint)sb.Capacity, out cch); // If this failed a second time, it shouldn't be because of an insufficient buffer. Assert.Implies(hr.Failed(), Win32Error.ERROR_INSUFFICIENT_BUFFER != hr); } if (HRESULT.S_OK == hr) { value = sb.ToString(); } return hr; }
/// <summary> /// Utility to set a binary property on an INativeContactProperties. /// </summary> /// <param name="contact">The INativeContactProperties to set the value on.</param> /// <param name="propertyName">The property to set.</param> /// <param name="binary">The value to set to the property.</param> /// <param name="binaryType">The mime-type of the value being applied.</param> /// <returns>HRESULT.</returns> /// <remarks> /// This is a thin wrapper over the COM INativeContactProperties::SetBinary to make it more easily consumable /// in .Net. Behavior and returned error codes should be similar to the native version. /// </remarks> public static HRESULT SetBinary(INativeContactProperties contact, string propertyName, string binaryType, Stream binary) { Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); using (var mstream = new ManagedIStream(binary)) { mstream.Seek(0, (int)SeekOrigin.Begin, IntPtr.Zero); return contact.SetBinary(propertyName, ContactValue.CGD_DEFAULT, binaryType, mstream); } }
public static HRESULT GetLabels(INativeContactProperties contact, string arrayNode, out List<string> labels) { HRESULT hr; labels = null; Verify.IsNotNull(contact, "contact"); using (var marshalable = new MarshalableDoubleNullString(Win32Value.MAX_PATH)) { uint cch; hr = contact.GetLabels(arrayNode, ContactValue.CGD_DEFAULT, marshalable.MarshaledString, marshalable.Capacity, out cch); // If we didn't have enough space for the node the first time through, try the bigger size. if (Win32Error.ERROR_INSUFFICIENT_BUFFER == hr) { // Reallocate to the size returned by the last GetLabels call. marshalable.Realloc(cch); hr = contact.GetLabels(arrayNode, ContactValue.CGD_DEFAULT, marshalable.MarshaledString, marshalable.Capacity, out cch); // If this failed a second time, it shouldn't be because of an insufficient buffer. Assert.Implies(hr.Failed(), Win32Error.ERROR_INSUFFICIENT_BUFFER != hr); } if (hr.Succeeded()) { labels = marshalable.ParsedStrings; } } return hr; }
public static HRESULT GetPropertyCollection(INativeContactProperties contact, string collection, string[] labels, bool anyLabelMatches, out IContactPropertyCollection propertyCollection) { Verify.IsNotNull(contact, "contact"); uint fAnyLabelMatches = anyLabelMatches ? Win32Value.TRUE : Win32Value.FALSE; using (var mlc = new MarshalableLabelCollection(labels)) { return contact.GetPropertyCollection(out propertyCollection, ContactValue.CGD_DEFAULT, collection, mlc.Count, mlc.MarshaledLabels, fAnyLabelMatches); } }
public static HRESULT GetDate(INativeContactProperties contact, string propertyName, bool ignoreDeletes, out DateTime value) { value = default(DateTime); Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); FILETIME ft; HRESULT hr = contact.GetDate(propertyName, ContactValue.CGD_DEFAULT, out ft); // If the caller doesn't care about deleted properties, convert the error code. if (ignoreDeletes && HRESULT.S_FALSE == hr) { hr = Win32Error.ERROR_PATH_NOT_FOUND; } if (HRESULT.S_OK == hr) { value = DateTimeFromFILETIME(ft); } return hr; }
public static HRESULT GetLabeledNode(INativeContactProperties contact, string collection, string[] labels, out string labeledNode) { labeledNode = null; Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(collection, "collection"); if (null == labels) { labels = new string[0]; } // Make a copy of the label set. // We're going to take two passes while trying to find the labeled value. // One has the Preferred label, the second doesn't. var preferredLabels = new string[labels.Length + 1]; labels.CopyTo(preferredLabels, 0); preferredLabels[labels.Length] = PropertyLabels.Preferred; HRESULT hr; IContactPropertyCollection propertyCollection = null; try { hr = GetPropertyCollection(contact, collection, preferredLabels, false, out propertyCollection); if (hr.Succeeded()) { // If a node satisfies this constraint, use it. hr = propertyCollection.Next(); if (HRESULT.S_FALSE == hr) { // Otherwise, try it again without the extra "Preferred" label. Utility.SafeRelease(ref propertyCollection); hr = GetPropertyCollection(contact, collection, labels, false, out propertyCollection); if (hr.Succeeded()) { // Does an array node exist with these labels? hr = propertyCollection.Next(); // There's nothing left to fall back on. S_FALSE implies this property doesn't exist. if (HRESULT.S_FALSE == hr) { hr = Win32Error.ERROR_PATH_NOT_FOUND; } } } } if (hr.Succeeded()) { hr = GetPropertyName(propertyCollection, out labeledNode); } } finally { Utility.SafeRelease(ref propertyCollection); } return hr; }
// There's a bug in Windows Contacts that simple extension array nodes return S_OK // instead of S_FALSE. This function happens to behave correctly anyways. public static bool DoesPropertyExist(INativeContactProperties contact, string propertyName) { Verify.IsNotNull(contact, "contact"); if (string.IsNullOrEmpty(propertyName)) { return false; } string dummy; HRESULT hr = GetString(contact, propertyName, false, out dummy); if (HRESULT.S_FALSE == hr) { // S_FALSE usually implies a deleted property, // but if it's an array node then it's present. return propertyName.EndsWith("]", StringComparison.Ordinal); } if (Win32Error.ERROR_PATH_NOT_FOUND == hr) { return false; } // Other errors are unexpected. hr.ThrowIfFailed("Error querying the property"); return true; }
public static HRESULT GetBinary(INativeContactProperties contact, string propertyName, bool ignoreDeletes, out string binaryType, out Stream binary) { binaryType = null; binary = null; Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); HRESULT hr; var sb = new StringBuilder((int)Win32Value.MAX_PATH); IStream stm = null; try { uint cch; hr = contact.GetBinary(propertyName, ContactValue.CGD_DEFAULT, sb, (uint)sb.Capacity, out cch, out stm); if (ignoreDeletes && HRESULT.S_FALSE == hr) { hr = Win32Error.ERROR_PATH_NOT_FOUND; } // If we didn't have enough space for the binaryType the first time through, try the bigger size. if (Win32Error.ERROR_INSUFFICIENT_BUFFER == hr) { Assert.IsNull(stm); sb.EnsureCapacity((int)cch); hr = contact.GetBinary(propertyName, ContactValue.CGD_DEFAULT, sb, (uint)sb.Capacity, out cch, out stm); // GetBinary shouldn't return ERROR_INSUFFICIENT_BUFFER if it's going to subsequently return S_FALSE. Assert.AreNotEqual(HRESULT.S_FALSE, hr); // If this failed a second time, it shouldn't be because of an insufficient buffer. Assert.Implies(hr.Failed(), Win32Error.ERROR_INSUFFICIENT_BUFFER != hr); } if (HRESULT.S_OK == hr) { binary = new ComStream(ref stm); binaryType = sb.ToString(); } } finally { Utility.SafeRelease(ref stm); } return hr; }
public static HRESULT DeleteProperty(INativeContactProperties contact, string propertyName) { Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(propertyName, "propertyName"); // COM APIs don't check for this. DeleteArrayNode should be used in this case. if (propertyName.EndsWith("]", StringComparison.Ordinal)) { return Win32Error.ERROR_INVALID_DATATYPE; } return contact.DeleteProperty(propertyName, ContactValue.CGD_DEFAULT); }
public static HRESULT DeleteLabels(INativeContactProperties contact, string nodeName) { Verify.IsNotNull(contact, "contact"); return contact.DeleteLabels(nodeName, ContactValue.CGD_DEFAULT); }
public static HRESULT CreateArrayNode(INativeContactProperties contact, string arrayName, bool appendNode, out string node) { node = null; Verify.IsNotNull(contact, "contact"); HRESULT hr; var sb = new StringBuilder((int)Win32Value.MAX_PATH); uint convertedAppend = appendNode ? Win32Value.TRUE : Win32Value.FALSE; uint cch; hr = contact.CreateArrayNode(arrayName, ContactValue.CGD_DEFAULT, convertedAppend, sb, (uint)sb.Capacity, out cch); // If we didn't have enough space for the node the first time through, try the bigger size. if (Win32Error.ERROR_INSUFFICIENT_BUFFER == hr) { sb.EnsureCapacity((int)cch); hr = contact.CreateArrayNode(arrayName, ContactValue.CGD_DEFAULT, convertedAppend, sb, (uint)sb.Capacity, out cch); // If this failed a second time, it shouldn't be because of an insufficient buffer. Assert.Implies(hr.Failed(), Win32Error.ERROR_INSUFFICIENT_BUFFER != hr); } if (hr.Succeeded()) { node = sb.ToString(); } return hr; }
public static HRESULT DeleteArrayNode(INativeContactProperties contact, string nodeName) { Verify.IsNotNull(contact, "contact"); Verify.IsNotNull(nodeName, "nodeName"); // COM APIs don't check for this. DeleteProperty should be used in this case. if (!nodeName.EndsWith("]")) { return (HRESULT)Win32Error.ERROR_INVALID_DATATYPE; } return contact.DeleteArrayNode(nodeName, ContactValue.CGD_DEFAULT); }
private VistaContactProperties(Stream stream, bool ownsStream) { Verify.IsNotNull(stream, "stream"); _nativeContact = new ContactRcw(); var persistStream = (IPersistStream)_nativeContact; stream.Seek(0, SeekOrigin.Begin); // COM APIs may keep the stream and rely on using it later. // Managed callers are likely to call dispose on it, which destroys it. // Need to create a copy of the stream and keep it alive and unchanged // for the lifetime of this object. if (ownsStream) { // This is our own copy. Don't need to dupe it. _streamCopy = stream; } else { _streamCopy = new MemoryStream(); Utility.CopyStream(_streamCopy, stream); } _istreamCopy = new ManagedIStream(_streamCopy); HRESULT hr = persistStream.Load(_istreamCopy); if (HRESULT.WC_E_SYNTAX == hr || HRESULT.WC_E_GREATERTHAN == hr || Win32Error.ERROR_INVALID_DATATYPE == hr) { throw new InvalidDataException("The data stream is of an invalid format"); } hr.ThrowIfFailed("An error occurred loading the contact"); //_modified = false; }