using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using Microsoft.Office.Interop.UccApi;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Threading;
using System.ComponentModel;
using System.Reflection;
namespace UccApiComponents
{
public partial class UccApiUtilities
{
// represents the success code, corresponds to S_OK code in COM
public const int S_OK = 0;
/// <summary>
/// structure holds int OUT param of IConnectionPoint.Advise
/// key is string built of HASH of event source interface, HASH of
/// event sink, and int pointer for IUnknown interface of event
/// source instance
/// </summary>
static Dictionary<string, int> cookieJar;
/// <summary>
/// constructor instantiates new empty dictionary
/// </summary>
static UccApiUtilities()
{
cookieJar = new Dictionary<string, int>();
}
/// <summary>
/// creates unique key value for cookie jar
/// </summary>
/// <param name="i">pointer to IUnknown interface of event source</param>
/// <param name="j">HASH of event sink class</param>
/// <param name="k">HASH of event source class</param>
/// <returns></returns>
static string StringKey(IntPtr i, int j, int k)
{
return i.ToString() + j.ToString() + k.ToString();
}
/// <summary>
/// establishes an advisory relationship between event
/// source connection point and provided event sink.
/// casts event source to IConnectionPointContainer to
/// obtain a connection point. Advises new connection
/// point of event sink (T)
/// </summary>
/// <typeparam name="T">Type of event sink</typeparam>
/// <param name="source">source of event</param>
/// <param name="sink">object implementing T</param>
public static void AdviseForEvents<T>(
source,
sink);
{
if (source == null || sink == null)
{
throw new ArgumentNullException("source", "AdviseForEvents<T>: Source and sink cannot be null");
}
IntPtr i = Marshal.GetIUnknownForObject(source);
int j = sink.GetHashCode(); //
int k = typeof(T).GetHashCode();
string key = StringKey(i, j, k);
if (cookieJar.ContainsKey(key))
{
return; // already advise the source of the sink.
}
IConnectionPoint cp;
int cookie;
IConnectionPointContainer container = (IConnectionPointContainer)source;
Guid guid = typeof(T).GUID;
container.FindConnectionPoint(ref guid, out cp);
cp.Advise(sink, out cookie);
cookieJar.Add(key, cookie);
}
/// <summary>
/// terminates an advisor connection previously established
/// </summary>
/// <typeparam name="T">type of event sink</typeparam>
/// <param name="source">event source</param>
/// <param name="sink">class instance implementing T</param>
public static void UnadviseForEvents<T>(
object source,
T sink)
{
if (source == null || sink == null)
{
throw new ArgumentNullException("source", "UnadviseForEvents<T>: Source and sink cannot be null");
}
IntPtr i = Marshal.GetIUnknownForObject(source);
int j = sink.GetHashCode();
int k = typeof(T).GetHashCode();
string key = StringKey(i, j, k);
//avoid exception, check to see if cookieJar
//has key value before referencing item using
//index syntax
if (cookieJar.ContainsKey(key))
{
int cookie = cookieJar[key];
IConnectionPointContainer container = (IConnectionPointContainer)source;
IConnectionPoint cp;
Guid guid = typeof(T).GUID;
container.FindConnectionPoint(ref guid, out cp);
cp.Unadvise(cookie);
cookieJar.Remove(key);
}
}
/// <summary>
/// public wrapper for advise
/// </summary>
/// <typeparam name="T">type of event sink</typeparam>
/// <param name="source">class instance event source</param>
/// <param name="sink">class instance implementing T</param>
public static void UCC_Advise<T>(object source, T sink)
{
AdviseForEvents<T>(source, sink);
}
/// <summary>
/// public wrapper for unadvise
/// </summary>
/// <typeparam name="T">type of event sink</typeparam>
/// <param name="source">class instance event source</param>
/// <param name="sink">class instance implementing T</param>
public static void UCC_Unadvise<T>(object source, T sink)
{
UnadviseForEvents<T>(source, sink);
}
/// <summary>
/// converts state availability Int to readable string
/// </summary>
/// <param name="avail">state availability</param>
/// <returns>availability string</returns>
public static string AvailabilityIntToString(int avail)
{
if (avail < 3000)
return "Unknown";
else if (avail < 6000)
return "Available";
else if (avail < 9000)
return "Busy";
else if (avail < 12000)
return "Do Not Disturb";
else if (avail < 18000)
return "Away";
else
return "Offline";
}
/// <summary>
/// Converts availability from a string to an integer.
/// </summary>
/// <param name="avail">String representation of availability</param>
/// <returns>Integer representation of availability</returns>
public static int AvailabilityStringToInt(string avail)
{
//TODO: Use string.compare
StringComparer strComparer =
StringComparer.Create(System.Globalization.CultureInfo.CurrentCulture, true);
if (strComparer.Compare(avail, "Available") == 0)
return 3500;
else if (strComparer.Compare(avail, "Busy") == 0)
return 6500;
else if (strComparer.Compare(avail, "Do Not Disturb") == 0)
return 9500;
else if (strComparer.Compare(avail, "Away") == 0)
return 15500;
else if (strComparer.Compare(avail, "Appear Offline") == 0)
return 18500;
else
return 0;
}
/// <summary>
/// Shows error by popping up a message box. This method maybe modified to log
/// errors.
/// </summary>
/// <param name="errorString">Error string to be shown or logged</param>
public static void ReportError(string errorString)
{
Debug(errorString);
}
public static UccOperationContext CreateOperationContext(int operationId, UccContext context)
{
UccOperationContext opCtx = new UccOperationContext();
opCtx.Initialize(operationId, context);
return opCtx;
}
// Firing events: calling an event handler with given event args in the specified execution context
public static void RaiseEvent(object exeContext,
MulticastDelegate mDelegate,
EventArgs eventArgs)
{
if (mDelegate == null)
return;
Delegate[] delegates = null;
delegates = mDelegate.GetInvocationList();
if (delegates == null)
return;
// Invoke delegates within their threads
foreach (Delegate _delegate in delegates)
{
object[] contextAndArgs = { exeContext, eventArgs };
(_delegate.Target as ISynchronizeInvoke).Invoke(_delegate, contextAndArgs);
}
}
public static void Trace(object exeContext, EventHandler<TraceEventArgs> eventHandler, string msg)
{
if (exeContext != null)
{
MulticastDelegate mDelegate = eventHandler as MulticastDelegate;
if (mDelegate != null)
{
RaiseEvent(exeContext, mDelegate, new TraceEventArgs(msg));
}
}
}
public static void Trace(string msg)
{
msg = DateTime.Now + ": " + msg.Replace("\n", Environment.NewLine);
StreamWriter sw = new StreamWriter(@"trace.txt", true);
sw.WriteLine(msg);
sw.Flush();
sw.Close();
}
public static string COMErrorMessage(System.Runtime.InteropServices.COMException ex)
{
if (ex == null)
return string.Empty;
return string.Format("COMException: {0}\n\tErrorCode: {1}\n\tStackTrace: {2}",
ex.Message, ex.ErrorCode, ex.StackTrace);
}
public static void Debug(string msg)
{
System.Diagnostics.Debug.WriteLine(msg);
}
}
}