/***********************************************************************\
* Virtuoso.Miranda.Plugins (Hyphen) *
* Provides a managed wrapper for API of IM client Miranda. *
* Copyright (C) 2006-2009 virtuoso *
* deml.tomas@seznam.cz *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
\***********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Virtuoso.Miranda.Plugins.Native;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Virtuoso.Miranda.Plugins.Resources;
using Virtuoso.Miranda.Plugins.Collections;
using System.Collections.ObjectModel;
using Virtuoso.Hyphen;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace Virtuoso.Miranda.Plugins.Infrastructure
{
public sealed class MirandaContext
{
#region Constants
private const string MS_SYSTEM_GETVERSIONTEXT = "Miranda/System/GetVersionText";
///
/// Returns Miranda's RTL/CRT function poiners to malloc() free() realloc() -- 0.1.2.2+
/// This is useful for preallocation of memory for use with Miranda's services
/// that Miranda can free -- or reallocation of a block of memory passed with a service.
/// Do not use with memory unless it is explicitly expected the memory *can*
/// or *shall* be used in this way. The passed structure is expected to have it's .cbSize initialised
/// wParam=0, lParam = (LPARAM) &MM_INTERFACE.
///
private const string MS_SYSTEM_GET_MMI = "Miranda/System/GetMMI";
#endregion
#region Fields
private static MirandaContext singleton;
private PluginManagerBase pluginManager;
private readonly ServiceCallInterceptionManager serviceInterceptors;
private readonly MirandaDatabase mirandaDatabase;
private ProtocolDictionary protocols;
private readonly MirandaPluginLink pluginLink;
private readonly ContactList contactList;
#endregion
#region .ctors
private MirandaContext(PluginManagerBase pluginManager, MirandaPluginLink mirandaLink, bool skipContextInfo)
{
if (mirandaLink == null)
throw new ArgumentNullException("mirandaLink");
this.pluginManager = pluginManager;
this.mirandaDatabase = new MirandaDatabase();
this.pluginLink = mirandaLink;
this.contactList = new ContactList();
this.serviceInterceptors = new ServiceCallInterceptionManager();
GetMMInterface();
PopulateEnvironmentInformation();
if (!skipContextInfo)
PopulateContextInformation();
else
this.protocols = new ProtocolDictionary(0);
}
///
/// Initializes a context from a plugin link.
///
///
///
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, bool skipContextPopulation)
{
InitializeCurrent(mirandaLink, null, skipContextPopulation);
}
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, PluginManagerBase pluginManager)
{
InitializeCurrent(mirandaLink, pluginManager, false);
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InitializeCurrent(MirandaPluginLink mirandaLink, PluginManagerBase pluginManager, bool skipContextPopulation)
{
if (singleton == null)
singleton = new MirandaContext(pluginManager, mirandaLink, skipContextPopulation);
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InitializeCurrent(MirandaContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (singleton == null)
singleton = context;
else
throw new InvalidOperationException();
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal static void InvalidateCurrent()
{
if (Initialized)
{
singleton.DetachPluginManager();
singleton = null;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal void AssociatePluginManager(PluginManagerBase manager)
{
if (manager == null)
throw new ArgumentNullException("manager");
pluginManager = manager;
}
[MethodImpl(MethodImplOptions.Synchronized)]
internal void DetachPluginManager()
{
pluginManager = null;
}
#endregion
#region Initialization
private void GetMMInterface()
{
mirandaMemoryManager = new MM_INTERFACE();
mirandaMemoryManager.Size = Marshal.SizeOf(typeof(MM_INTERFACE));
UnmanagedStructHandle mmiHandle = new UnmanagedStructHandle(ref mirandaMemoryManager);
try
{
if (CallService(MS_SYSTEM_GET_MMI, IntPtr.Zero, mmiHandle.IntPtr) == CallbackResult.Success)
mmiHandle.MarshalBack(out mirandaMemoryManager);
else
throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MS_SYSTEM_GET_MMI, "1"));
}
finally
{
mmiHandle.Free();
}
}
internal void PopulateContextInformation()
{
PopulateNetworkProtocols();
}
private unsafe void PopulateNetworkProtocols()
{
try
{
int count;
PROTOCOLDESCRIPTOR** pointerArrayPtr;
int result = CallServiceUnsafe(MirandaServices.MS_PROTO_ENUMPROTOCOLS, &count, &pointerArrayPtr);
if (result != 0) throw new MirandaException(String.Format(TextResources.ExceptionMsg_Formatable2_MirandaServiceReturnedFailure, MirandaServices.MS_PROTO_ENUMPROTOCOLS, result.ToString()));
ProtocolDictionary protocols = new ProtocolDictionary(count);
for (int i = 0; i < count; i++)
{
// *(ptr_to_array_of_ptrs + i * sizeof(PROTOCOLDESCRIPTOR)) = *ptr_to_ptr = *ptr = data
PROTOCOLDESCRIPTOR nativeDescriptor = **(((PROTOCOLDESCRIPTOR**)pointerArrayPtr) + i);
Protocol protocol = new Protocol(ref nativeDescriptor);
protocols.Add(protocol.Name, protocol);
}
this.protocols = protocols;
}
catch (Exception)
{
this.protocols = new ProtocolDictionary(0);
}
}
private void PopulateEnvironmentInformation()
{
InteropBuffer buffer = InteropBufferPool.AcquireBuffer();
try
{
buffer.Lock();
int result = CallService(MS_SYSTEM_GETVERSIONTEXT, buffer.SizeAsUIntPtr, buffer.IntPtr);
Debug.Assert(result == 0);
if (result == 0 && Translate.ToString(buffer.IntPtr, StringEncoding.Ansi).IndexOf("Unicode") != -1)
MirandaEnvironment.MirandaStringEncoding = StringEncoding.Unicode;
else
MirandaEnvironment.MirandaStringEncoding = StringEncoding.Ansi;
}
finally
{
buffer.Unlock();
InteropBufferPool.ReleaseBuffer(buffer);
}
MirandaEnvironment.MirandaVersion = Translate.FromMirandaVersion((uint)CallService(MirandaServices.MS_SYSTEM_GETVERSION));
}
#endregion
#region Properties
internal MirandaPluginLink PluginLink
{
get
{
return this.pluginLink;
}
}
private MM_INTERFACE mirandaMemoryManager;
internal MM_INTERFACE MirandaMemoryManager
{
get { return mirandaMemoryManager; }
}
internal PluginManagerBase PluginManager
{
get
{
if (this.pluginManager == null)
throw new InvalidOperationException("No plugin manager associated with this context.");
return this.pluginManager;
}
}
public bool HasPluginManager
{
get
{
return this.pluginManager != null;
}
}
public static MirandaContext Current
{
get
{
if (singleton == null)
throw new InvalidOperationException(TextResources.ExceptionMsg_MirandaContextNotAvailable);
return singleton;
}
}
public static bool Initialized
{
get
{
return singleton != null;
}
}
public ServiceCallInterceptionManager ServiceCallInterceptors
{
get
{
return this.serviceInterceptors;
}
}
public MirandaDatabase MirandaDatabase
{
get
{
return this.mirandaDatabase;
}
}
public ProtocolDictionary Protocols
{
get
{
return this.protocols;
}
}
public ContactList ContactList
{
get { return contactList; }
}
#endregion
#region Events
public event EventHandler ModulesLoaded;
internal void RaiseModulesLoadedEvent()
{
if (ModulesLoaded != null)
ModulesLoaded(this, EventArgs.Empty);
}
internal event EventHandler IsolatedModePluginsUnloading;
internal void RaiseIsolatedModePluginsUnloadingEvent()
{
if (IsolatedModePluginsUnloading != null)
IsolatedModePluginsUnloading(null, EventArgs.Empty);
}
#endregion
#region CallService
public int CallService(string serviceName)
{
return CallService(serviceName, UIntPtr.Zero, IntPtr.Zero, false);
}
public int CallService(string serviceName, IntPtr wParam, IntPtr lParam)
{
return CallService(serviceName, Translate.ToHandle(wParam), lParam, false);
}
[CLSCompliant(false)]
public int CallService(string serviceName, UIntPtr wParam, IntPtr lParam)
{
return CallService(serviceName, wParam, lParam, false);
}
internal int CallService(string serviceName, UIntPtr wParam, IntPtr lParam, bool noInterception)
{
if (String.IsNullOrEmpty(serviceName))
throw new ArgumentNullException("service");
int returnCode =
serviceInterceptors.RequiresInterception(serviceName) && !noInterception ?
serviceInterceptors[serviceName](wParam, lParam) : pluginLink.NativePluginLink.CallService(serviceName, wParam, lParam);
return returnCode;
}
internal unsafe int CallServiceUnsafe(string serviceName, void* wParam, void* lParam)
{
return pluginLink.CallServiceUnsafe(serviceName, wParam, lParam);
}
#endregion
}
}