check point
This commit is contained in:
279
framework/MaterialSkin.Core/Gesture/GestureEventArgs.cs
Normal file
279
framework/MaterialSkin.Core/Gesture/GestureEventArgs.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
#region The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2011 Robert Prouse http://www.alteridem.net
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
// Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
#endregion
|
||||
|
||||
#region Using Directives
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace MaterialSkin.Gesture
|
||||
{
|
||||
#region GestureEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all the gesture based events
|
||||
/// </summary>
|
||||
public abstract class GestureEventArgs : EventArgs
|
||||
{
|
||||
internal GestureEventArgs( GestureInfo info )
|
||||
{
|
||||
Location = new Point( info.location.x, info.location.y );
|
||||
Info = info;
|
||||
Handled = true;
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected static int LoDWord( IntPtr lParam )
|
||||
{
|
||||
return LoDWord( lParam.ToInt64() );
|
||||
}
|
||||
|
||||
protected static int HiDWord( IntPtr lParam )
|
||||
{
|
||||
return HiDWord( lParam.ToInt64() );
|
||||
}
|
||||
|
||||
protected static int LoDWord( long l )
|
||||
{
|
||||
return (int)(l & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
protected static int HiDWord( long l )
|
||||
{
|
||||
return (int)((l >> 32) & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
protected static short LoWord( int i )
|
||||
{
|
||||
return (short)(i & 0xFFFF);
|
||||
}
|
||||
|
||||
protected static short HiWord( int i )
|
||||
{
|
||||
return (short)((i >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
protected GestureInfo Info { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location of the gesture in Screen (not client) coordinates.
|
||||
/// </summary>
|
||||
public Point Location { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="GestureEventArgs"/> is beginning.
|
||||
/// </summary>
|
||||
public bool Begin
|
||||
{
|
||||
get { return Info.Begin; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="GestureEventArgs"/> is ending
|
||||
/// </summary>
|
||||
public bool End
|
||||
{
|
||||
get { return Info.End; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the window message was handled. Set this to false if you don't handle the message.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PanEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Event for the Pan gesture
|
||||
/// </summary>
|
||||
public class PanEventArgs : GestureEventArgs
|
||||
{
|
||||
internal PanEventArgs( GestureInfo info, Point lastPanPoint )
|
||||
: base( info )
|
||||
{
|
||||
int hiword = HiDWord( info.arguments );
|
||||
InertiaVector = new Point( LoWord( hiword ), HiWord( hiword ) );
|
||||
PanOffset = new Point( Location.X - lastPanPoint.X, Location.Y - lastPanPoint.Y );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="GestureEventArgs"/> has triggered inertia.
|
||||
/// </summary>
|
||||
public bool Inertia
|
||||
{
|
||||
get { return Info.Inertia; }
|
||||
}
|
||||
|
||||
public Point InertiaVector { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pan offset since the last pan message.
|
||||
/// </summary>
|
||||
public Point PanOffset { get; private set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ZoomEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Event for the Zoom gesture
|
||||
/// </summary>
|
||||
public class ZoomEventArgs : GestureEventArgs
|
||||
{
|
||||
internal ZoomEventArgs( GestureInfo info, long lastZoomDistance )
|
||||
: base( info )
|
||||
{
|
||||
Distance = info.arguments;
|
||||
PercentChange = (double)Distance / lastZoomDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the distance between the two points as they are being zoomed.
|
||||
/// </summary>
|
||||
public long Distance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the percent changed since the last zoom message
|
||||
/// </summary>
|
||||
public double PercentChange { get; private set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PressAndTapEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Event for the Press and Tap gesture
|
||||
/// </summary>
|
||||
public class PressAndTapEventArgs : GestureEventArgs
|
||||
{
|
||||
internal PressAndTapEventArgs( GestureInfo info )
|
||||
: base( info )
|
||||
{
|
||||
int pointsStruct = LoDWord( info.arguments );
|
||||
Distance = new Point( LoWord( pointsStruct ), HiWord( pointsStruct ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the distance between the two points.
|
||||
/// </summary>
|
||||
public Point Distance { get; private set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RotateEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Event for the Rotate gesture
|
||||
/// </summary>
|
||||
public class RotateEventArgs : GestureEventArgs
|
||||
{
|
||||
internal RotateEventArgs( GestureInfo info, double lastRotation )
|
||||
: base( info )
|
||||
{
|
||||
int loword = LoDWord( info.arguments );
|
||||
TotalAngle = RotateAngleFromArgument( loword );
|
||||
Angle = TotalAngle - lastRotation;
|
||||
string msg = string.Format("Total:{0} Angle:{1} Last:{2}", TotalAngle, Angle, lastRotation );
|
||||
System.Diagnostics.Debug.WriteLine( msg );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gesture argument helper that converts an argument to a rotation angle.
|
||||
/// </summary>
|
||||
/// <param name="arg">The argument to convert. Should be an unsigned 16-bit value.</param>
|
||||
/// <returns></returns>
|
||||
private static double RotateAngleFromArgument( int arg )
|
||||
{
|
||||
return ((arg / 65535.0) * 4.0 * Math.PI) - 2.0 * Math.PI;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the angle of rotation in Radians since the beginning of the gesture
|
||||
/// </summary>
|
||||
public double TotalAngle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the angle of rotation in Degrees since the beginning of the gesture
|
||||
/// </summary>
|
||||
public double TotalDegrees
|
||||
{
|
||||
get { return RadiandsToDegrees( TotalAngle ); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the angle of rotation in Radians since the last rotation message
|
||||
/// </summary>
|
||||
public double Angle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the angle of rotation in Degrees since the last rotation message
|
||||
/// </summary>
|
||||
public double Degrees
|
||||
{
|
||||
get { return RadiandsToDegrees( Angle ); }
|
||||
}
|
||||
|
||||
private double RadiandsToDegrees( double radians )
|
||||
{
|
||||
return radians * 180.0 / Math.PI;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TwoFingerTapEventArgs Class
|
||||
|
||||
/// <summary>
|
||||
/// Base class for the Two Finger Tap gesture
|
||||
/// </summary>
|
||||
public class TwoFingerTapEventArgs : GestureEventArgs
|
||||
{
|
||||
internal TwoFingerTapEventArgs( GestureInfo info )
|
||||
: base( info )
|
||||
{
|
||||
Distance = info.arguments;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the distance between the two points.
|
||||
/// </summary>
|
||||
public long Distance { get; private set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
446
framework/MaterialSkin.Core/Gesture/GestureListener.cs
Normal file
446
framework/MaterialSkin.Core/Gesture/GestureListener.cs
Normal file
@@ -0,0 +1,446 @@
|
||||
#region The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2011 Robert Prouse http://www.alteridem.net
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
// Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
#endregion
|
||||
|
||||
#region Using Directives
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace MaterialSkin.Gesture
|
||||
{
|
||||
[PermissionSet( SecurityAction.Demand, Name = "FullTrust" )]
|
||||
public sealed class GestureListener : NativeWindow
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
// Saved state
|
||||
private Point _lastPanPoint;
|
||||
private double _lastRotation;
|
||||
private long _lastZoom;
|
||||
|
||||
private readonly Control _parent;
|
||||
private readonly GestureConfig[] m_configs;
|
||||
private int _touchInputSize;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Events
|
||||
|
||||
public event EventHandler<PanEventArgs> Pan;
|
||||
public event EventHandler<PressAndTapEventArgs> PressAndTap;
|
||||
public event EventHandler<RotateEventArgs> Rotate;
|
||||
public event EventHandler<TwoFingerTapEventArgs> TwoFingerTap;
|
||||
public event EventHandler<ZoomEventArgs> Zoom;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GestureListener"/> class to receive all gestures.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent.</param>
|
||||
public GestureListener( Control parent )
|
||||
: this( parent, new[] { new GestureConfig( 0, GestureConfigurationFlag.GC_ALLGESTURES, 0 ) } )
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GestureListener"/> class to receive specific gestures.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="configs">The gesture configurations.</param>
|
||||
public GestureListener( Control parent, GestureConfig[] configs )
|
||||
{
|
||||
if ( parent.IsHandleCreated )
|
||||
{
|
||||
Initialize( parent );
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.HandleCreated += OnHandleCreated;
|
||||
}
|
||||
parent.HandleDestroyed += OnHandleDestroyed;
|
||||
|
||||
_parent = parent;
|
||||
m_configs = configs;
|
||||
_touchInputSize = Marshal.SizeOf(new TOUCHINPUT());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
[DllImport("user32")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool RegisterTouchWindow(System.IntPtr hWnd, ulong ulFlags);
|
||||
private void Initialize( Control parent )
|
||||
{
|
||||
AssignHandle( parent.Handle );
|
||||
NativeMethods.SetGestureConfig( parent.Handle, m_configs );
|
||||
|
||||
}
|
||||
|
||||
public void LoadMultitouch()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
Action a = () =>
|
||||
{
|
||||
if (!RegisterTouchWindow(_parent.Handle, 0))
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
_parent.Invoke(a);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
private void OnHandleCreated( object sender, EventArgs e )
|
||||
{
|
||||
// Window is now created, assign handle to NativeWindow.
|
||||
var control = sender as Control;
|
||||
if ( control != null )
|
||||
{
|
||||
Initialize( control );
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHandleDestroyed( object sender, EventArgs e )
|
||||
{
|
||||
// Window was destroyed, release hook.
|
||||
ReleaseHandle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WndProc
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the default window procedure associated with this window.
|
||||
/// </summary>
|
||||
/// <param name="m">A <see cref="T:System.Windows.Forms.Message"/> that is associated with the current Windows message.</param>
|
||||
[PermissionSet( SecurityAction.Demand, Name = "FullTrust" )]
|
||||
protected override void WndProc( ref Message m )
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
// Listen for operating system messages
|
||||
switch ( m.Msg )
|
||||
{
|
||||
case WindowMessage.WM_GESTURE:
|
||||
GestureInfo info;
|
||||
if ( NativeMethods.GetGestureInfo( m.LParam, out info ) )
|
||||
{
|
||||
switch ( (GestureId)info.id )
|
||||
{
|
||||
case GestureId.Pan:
|
||||
handled = OnPan( info );
|
||||
break;
|
||||
case GestureId.PressAndTap:
|
||||
handled = OnPressAndTap( info );
|
||||
break;
|
||||
case GestureId.Rotate:
|
||||
handled = OnRotate( info );
|
||||
break;
|
||||
case GestureId.TwoFingerTap:
|
||||
handled = OnTwoFingerTap( info );
|
||||
break;
|
||||
case GestureId.Zoom:
|
||||
handled = OnZoom( info );
|
||||
break;
|
||||
}
|
||||
if ( handled )
|
||||
{
|
||||
NativeMethods.CloseGestureInfoHandle( m.LParam );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WindowMessage.WM_TOUCH:
|
||||
MessageBox.Show("touch");
|
||||
this.DecodeTouch(ref m);
|
||||
break;
|
||||
//case WindowMessage.WM_POINTERUPDATE:
|
||||
// MessageBox.Show("ptr");
|
||||
// break;
|
||||
}
|
||||
if ( !handled )
|
||||
{
|
||||
base.WndProc( ref m );
|
||||
}
|
||||
}
|
||||
private static int LoWord(int number)
|
||||
{
|
||||
return (number & 0xffff);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct TOUCHINPUT
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
public System.IntPtr hSource;
|
||||
public int dwID;
|
||||
public int dwFlags;
|
||||
public int dwMask;
|
||||
public int dwTime;
|
||||
public System.IntPtr dwExtraInfo;
|
||||
public int cxContact;
|
||||
public int cyContact;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct POINTS
|
||||
{
|
||||
public short x;
|
||||
public short y;
|
||||
}
|
||||
public event EventHandler<WMTouchEventArgs> Touchdown; // touch down event handler
|
||||
public event EventHandler<WMTouchEventArgs> Touchup; // touch up event handler
|
||||
public event EventHandler<WMTouchEventArgs> TouchMove; // touch move event handler
|
||||
|
||||
// EventArgs passed to Touch handlers
|
||||
public class WMTouchEventArgs : System.EventArgs
|
||||
{
|
||||
// Private data members
|
||||
private int x; // touch x client coordinate in pixels
|
||||
private int y; // touch y client coordinate in pixels
|
||||
private int id; // contact ID
|
||||
private int mask; // mask which fields in the structure are valid
|
||||
private int flags; // flags
|
||||
private int time; // touch event time
|
||||
private int contactX; // x size of the contact area in pixels
|
||||
private int contactY; // y size of the contact area in pixels
|
||||
|
||||
// Access to data members
|
||||
public int LocationX
|
||||
{
|
||||
get { return x; }
|
||||
set { x = value; }
|
||||
}
|
||||
public int LocationY
|
||||
{
|
||||
get { return y; }
|
||||
set { y = value; }
|
||||
}
|
||||
public int Id
|
||||
{
|
||||
get { return id; }
|
||||
set { id = value; }
|
||||
}
|
||||
public int Flags
|
||||
{
|
||||
get { return flags; }
|
||||
set { flags = value; }
|
||||
}
|
||||
public int Mask
|
||||
{
|
||||
get { return mask; }
|
||||
set { mask = value; }
|
||||
}
|
||||
public int Time
|
||||
{
|
||||
get { return time; }
|
||||
set { time = value; }
|
||||
}
|
||||
public int ContactX
|
||||
{
|
||||
get { return contactX; }
|
||||
set { contactX = value; }
|
||||
}
|
||||
public int ContactY
|
||||
{
|
||||
get { return contactY; }
|
||||
set { contactY = value; }
|
||||
}
|
||||
public bool IsPrimaryContact
|
||||
{
|
||||
get { return (flags & WindowMessage.TOUCHEVENTF_PRIMARY) != 0; }
|
||||
}
|
||||
|
||||
// Constructor
|
||||
public WMTouchEventArgs()
|
||||
{
|
||||
}
|
||||
}
|
||||
[DllImport("user32")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetTouchInputInfo(System.IntPtr hTouchInput, int cInputs, [In, Out] TOUCHINPUT[] pInputs, int cbSize);
|
||||
[DllImport("user32")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern void CloseTouchInputHandle(System.IntPtr lParam);
|
||||
public bool DecodeTouch(ref Message m)
|
||||
{
|
||||
// More than one touchinput may be associated with a touch message,
|
||||
// so an array is needed to get all event information.
|
||||
int inputCount = LoWord(m.WParam.ToInt32()); // Number of touch inputs, actual per-contact messages
|
||||
|
||||
TOUCHINPUT[] inputs; // Array of TOUCHINPUT structures
|
||||
inputs = new TOUCHINPUT[inputCount]; // Allocate the storage for the parameters of the per-contact messages
|
||||
|
||||
// Unpack message parameters into the array of TOUCHINPUT structures, each
|
||||
// representing a message for one single contact.
|
||||
if (!GetTouchInputInfo(m.LParam, inputCount, inputs, _touchInputSize))
|
||||
{
|
||||
// Get touch info failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
// For each contact, dispatch the message to the appropriate message
|
||||
// handler.
|
||||
bool handled = false; // Boolean, is message handled
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
TOUCHINPUT ti = inputs[i];
|
||||
|
||||
// Assign a handler to this message.
|
||||
EventHandler<WMTouchEventArgs> handler = null; // Touch event handler
|
||||
if ((ti.dwFlags & WindowMessage.TOUCHEVENTF_DOWN) != 0)
|
||||
{
|
||||
handler = Touchdown;
|
||||
}
|
||||
else if ((ti.dwFlags & WindowMessage.TOUCHEVENTF_UP) != 0)
|
||||
{
|
||||
handler = Touchup;
|
||||
}
|
||||
else if ((ti.dwFlags & WindowMessage.TOUCHEVENTF_MOVE) != 0)
|
||||
{
|
||||
handler = TouchMove;
|
||||
}
|
||||
|
||||
// Convert message parameters into touch event arguments and handle the event.
|
||||
if (handler != null)
|
||||
{
|
||||
// Convert the raw touchinput message into a touchevent.
|
||||
WMTouchEventArgs te = new WMTouchEventArgs(); // Touch event arguments
|
||||
|
||||
// TOUCHINFO point coordinates and contact size is in 1/100 of a pixel; convert it to pixels.
|
||||
// Also convert screen to client coordinates.
|
||||
te.ContactY = ti.cyContact / 100;
|
||||
te.ContactX = ti.cxContact / 100;
|
||||
te.Id = ti.dwID;
|
||||
{
|
||||
Point pt = _parent.PointToClient(new Point(ti.x / 100, ti.y / 100));
|
||||
te.LocationX = pt.X;
|
||||
te.LocationY = pt.Y;
|
||||
}
|
||||
te.Time = ti.dwTime;
|
||||
te.Mask = ti.dwMask;
|
||||
te.Flags = ti.dwFlags;
|
||||
|
||||
// Invoke the event handler.
|
||||
handler(this, te);
|
||||
|
||||
// Mark this event as handled.
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
CloseTouchInputHandle(m.LParam);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
private bool OnPan( GestureInfo info )
|
||||
{
|
||||
if ( Pan != null )
|
||||
{
|
||||
if ( info.Begin )
|
||||
{
|
||||
_lastPanPoint = new Point( info.location.x, info.location.y );
|
||||
}
|
||||
var args = new PanEventArgs( info, _lastPanPoint );
|
||||
_lastPanPoint = new Point( info.location.x, info.location.y );
|
||||
Pan( this, args );
|
||||
return args.Handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool OnPressAndTap( GestureInfo info )
|
||||
{
|
||||
if ( PressAndTap != null )
|
||||
{
|
||||
var args = new PressAndTapEventArgs( info );
|
||||
PressAndTap( this, args );
|
||||
return args.Handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool OnRotate( GestureInfo info )
|
||||
{
|
||||
if ( Rotate != null )
|
||||
{
|
||||
if ( info.Begin )
|
||||
{
|
||||
_lastRotation = 0;
|
||||
}
|
||||
var args = new RotateEventArgs( info, _lastRotation );
|
||||
if ( !info.Begin )
|
||||
{
|
||||
// First rotation is the angle the fingers are at, so don't use it
|
||||
_lastRotation = args.TotalAngle;
|
||||
}
|
||||
Rotate( this, args );
|
||||
return args.Handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool OnTwoFingerTap( GestureInfo info )
|
||||
{
|
||||
if ( TwoFingerTap != null )
|
||||
{
|
||||
var args = new TwoFingerTapEventArgs( info );
|
||||
TwoFingerTap( this, args );
|
||||
return args.Handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool OnZoom( GestureInfo info )
|
||||
{
|
||||
if ( Zoom != null )
|
||||
{
|
||||
if ( info.Begin )
|
||||
{
|
||||
_lastZoom = info.arguments;
|
||||
}
|
||||
var args = new ZoomEventArgs( info, _lastZoom );
|
||||
_lastZoom = args.Distance;
|
||||
Zoom( this, args );
|
||||
return args.Handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
341
framework/MaterialSkin.Core/Gesture/NativeMethods.cs
Normal file
341
framework/MaterialSkin.Core/Gesture/NativeMethods.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
#region The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2011 Robert Prouse http://www.alteridem.net
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
// Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
#endregion
|
||||
|
||||
#region Using Directives
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace MaterialSkin.Gesture
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
#region Private Delegates
|
||||
|
||||
[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
|
||||
private delegate bool GetGestureInfoPtr( IntPtr gestureInfoHandle, ref GestureInfo pGestureInfo );
|
||||
|
||||
[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
|
||||
private delegate bool CloseGestureInfoHandlePtr( IntPtr gestureInfoHandle );
|
||||
|
||||
[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
|
||||
private delegate bool SetGestureConfigPtr( IntPtr hwnd, uint reserved, uint ids, GestureConfig[] configs, uint size );
|
||||
|
||||
private static readonly GetGestureInfoPtr _pGetGestureInfoPtr;
|
||||
private static readonly CloseGestureInfoHandlePtr _pCloseGestureInfoHandle;
|
||||
private static readonly SetGestureConfigPtr _pSetGestureConfig;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Construction
|
||||
|
||||
static NativeMethods()
|
||||
{
|
||||
var user32 = new UnmanagedLibrary( "user32" );
|
||||
_pGetGestureInfoPtr = user32.GetUnmanagedFunction<GetGestureInfoPtr>( "GetGestureInfo" );
|
||||
_pCloseGestureInfoHandle = user32.GetUnmanagedFunction<CloseGestureInfoHandlePtr>( "CloseGestureInfoHandle" );
|
||||
_pSetGestureConfig = user32.GetUnmanagedFunction<SetGestureConfigPtr>( "SetGestureConfig" );
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Interface
|
||||
|
||||
/// <summary>
|
||||
/// Registers the HWND to receive all gestures.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd353231%28v=vs.85%29.aspx
|
||||
/// </remarks>
|
||||
/// <param name="hwnd">The HWND.</param>
|
||||
/// <returns></returns>
|
||||
public static bool SetGestureConfig( IntPtr hwnd )
|
||||
{
|
||||
if ( _pSetGestureConfig == null )
|
||||
return false;
|
||||
|
||||
var configs = new[] { new GestureConfig( 0, GestureConfigurationFlag.GC_ALLGESTURES, 0 ) };
|
||||
return SetGestureConfig(hwnd, configs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the HWND to receive specific gestures.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd353231%28v=vs.85%29.aspx
|
||||
/// </remarks>
|
||||
/// <param name="hwnd">The HWND.</param>
|
||||
/// <param name="configs">The gesture configurations</param>
|
||||
/// <returns></returns>
|
||||
public static bool SetGestureConfig( IntPtr hwnd, GestureConfig[] configs )
|
||||
{
|
||||
return _pSetGestureConfig( hwnd, 0, 1, configs, (uint)Marshal.SizeOf( typeof( GestureConfig ) ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the gesture info.
|
||||
/// </summary>
|
||||
/// <param name="gestureInfoHandle">The gesture info handle.</param>
|
||||
/// <param name="gestureInfo">The gesture info.</param>
|
||||
/// <returns></returns>
|
||||
public static bool GetGestureInfo( IntPtr gestureInfoHandle, out GestureInfo gestureInfo )
|
||||
{
|
||||
gestureInfo = new GestureInfo();
|
||||
|
||||
if ( _pGetGestureInfoPtr == null )
|
||||
return false;
|
||||
|
||||
gestureInfo.size = Marshal.SizeOf( gestureInfo );
|
||||
return _pGetGestureInfoPtr( gestureInfoHandle, ref gestureInfo );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the gesture info handle.
|
||||
/// </summary>
|
||||
/// <param name="gestureInfoHandle">The gesture info handle.</param>
|
||||
/// <returns></returns>
|
||||
public static bool CloseGestureInfoHandle( IntPtr gestureInfoHandle )
|
||||
{
|
||||
if ( _pCloseGestureInfoHandle == null )
|
||||
return false;
|
||||
|
||||
return _pCloseGestureInfoHandle( gestureInfoHandle );
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gesture configuration flags
|
||||
/// </summary>
|
||||
internal static class GestureConfigurationFlag
|
||||
{
|
||||
public const int GC_ALLGESTURES = 0x00000001;
|
||||
public const int GC_ZOOM = 0x00000001;
|
||||
public const int GC_PAN = 0x00000001;
|
||||
public const int GC_PAN_WITH_SINGLE_FINGER_VERTICALLY = 0x00000002;
|
||||
public const int GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY = 0x00000004;
|
||||
public const int GC_PAN_WITH_GUTTER = 0x00000008;
|
||||
public const int GC_PAN_WITH_INERTIA = 0x00000010;
|
||||
public const int GC_ROTATE = 0x00000001;
|
||||
public const int GC_TWOFINGERTAP = 0x00000001;
|
||||
public const int GC_PRESSANDTAP = 0x00000001;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gesture flags - GestureInfo.flags
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum GestureFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// GF_BEGIN
|
||||
/// </summary>
|
||||
Begin = 0x1,
|
||||
/// <summary>
|
||||
/// GF_INERTIA
|
||||
/// </summary>
|
||||
Inertia = 0x2,
|
||||
/// <summary>
|
||||
/// GF_END
|
||||
/// </summary>
|
||||
End = 0x4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gesture IDs - GestureInfo.id
|
||||
/// </summary>
|
||||
public enum GestureId
|
||||
{
|
||||
/// <summary>
|
||||
/// GID_BEGIN
|
||||
/// </summary>
|
||||
Begin = 1,
|
||||
/// <summary>
|
||||
/// GID_END
|
||||
/// </summary>
|
||||
End = 2,
|
||||
/// <summary>
|
||||
/// GID_ZOOM
|
||||
/// </summary>
|
||||
Zoom = 3,
|
||||
/// <summary>
|
||||
/// GID_PAN
|
||||
/// </summary>
|
||||
Pan = 4,
|
||||
/// <summary>
|
||||
/// GID_ROTATE
|
||||
/// </summary>
|
||||
Rotate = 5,
|
||||
/// <summary>
|
||||
/// GID_TWOFINGERTAP
|
||||
/// </summary>
|
||||
TwoFingerTap = 6,
|
||||
/// <summary>
|
||||
/// GID_PRESSANDTAP
|
||||
/// </summary>
|
||||
PressAndTap = 7
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Window Messages
|
||||
/// </summary>
|
||||
internal static class WindowMessage
|
||||
{
|
||||
public const int WM_TOUCH = 0x0240;
|
||||
public const int WM_POINTERUPDATE =0x0245;
|
||||
public const int WM_GESTURE = 0x0119;
|
||||
public const int WM_GESTURENOTIFY = 0x011A;
|
||||
public const int TOUCHEVENTF_MOVE = 0x0001;
|
||||
public const int TOUCHEVENTF_DOWN = 0x0002;
|
||||
public const int TOUCHEVENTF_UP = 0x0004;
|
||||
public const int TOUCHEVENTF_INRANGE = 0x0008;
|
||||
public const int TOUCHEVENTF_PRIMARY = 0x0010;
|
||||
public const int TOUCHEVENTF_NOCOALESCE = 0x0020;
|
||||
public const int TOUCHEVENTF_PEN = 0x0040;
|
||||
|
||||
// Touch input mask values (TOUCHINPUT.dwMask) [winuser.h]
|
||||
public const int TOUCHINPUTMASKF_TIMEFROMSYSTEM = 0x0001; // the dwTime field contains a system generated value
|
||||
public const int TOUCHINPUTMASKF_EXTRAINFO = 0x0002; // the dwExtraInfo field is valid
|
||||
public const int TOUCHINPUTMASKF_CONTACTAREA = 0x0004; // the cxContact and cyContact fields are valid
|
||||
|
||||
|
||||
}
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct Points
|
||||
{
|
||||
public short x;
|
||||
public short y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gesture configuration structure
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used in SetGestureConfig and GetGestureConfig
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd353231%28v=vs.85%29.aspx
|
||||
/// </remarks>
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct GestureConfig
|
||||
{
|
||||
public GestureConfig( uint id, uint want, uint block )
|
||||
{
|
||||
Id = id;
|
||||
Want = want;
|
||||
Block = block;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The identifier for the type of configuration that will have messages enabled or disabled.
|
||||
/// </summary>
|
||||
public uint Id;
|
||||
|
||||
/// <summary>
|
||||
/// The messages to enable.
|
||||
/// </summary>
|
||||
public uint Want;
|
||||
|
||||
/// <summary>
|
||||
/// The messages to disable.
|
||||
/// </summary>
|
||||
public uint Block;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores information about a gesture.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// - Pass the HGESTUREINFO received in the WM_GESTURE message lParam into the
|
||||
/// GetGestureInfo function to retrieve this information.
|
||||
/// - If cbExtraArgs is non-zero, pass the HGESTUREINFO received in the WM_GESTURE
|
||||
/// message lParam into the GetGestureExtraArgs function to retrieve extended
|
||||
/// argument information.
|
||||
/// </remarks>
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct GestureInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of the structure, in bytes. The caller must set this.
|
||||
/// </summary>
|
||||
public int size;
|
||||
/// <summary>
|
||||
/// The state of the gesture. Contains GestureFlags.
|
||||
/// </summary>
|
||||
public int flags;
|
||||
/// <summary>
|
||||
/// The identifier of the gesture command. Contains GestureId.
|
||||
/// </summary>
|
||||
public int id;
|
||||
/// <summary>
|
||||
/// A handle to the window that is targeted by this gesture.
|
||||
/// </summary>
|
||||
public IntPtr hwnd;
|
||||
/// <summary>
|
||||
/// A Points structure containing the coordinates associated with the gesture. These coordinates are always relative to the origin of the screen.
|
||||
/// </summary>
|
||||
public Points location;
|
||||
/// <summary>
|
||||
/// An internally used identifier for the structure.
|
||||
/// </summary>
|
||||
public int instanceId;
|
||||
/// <summary>
|
||||
/// An internally used identifier for the sequence.
|
||||
/// </summary>
|
||||
public int sequenceId;
|
||||
/// <summary>
|
||||
/// A 64-bit unsigned integer that contains the arguments for gestures that fit into 8 bytes.
|
||||
/// </summary>
|
||||
public Int64 arguments;
|
||||
/// <summary>
|
||||
/// The size, in bytes, of extra arguments that accompany this gesture.
|
||||
/// </summary>
|
||||
public int extraArguments;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="GestureFlags"/> Begin is set.
|
||||
/// </summary>
|
||||
public bool Begin
|
||||
{
|
||||
get { return ((GestureFlags)flags & GestureFlags.Begin) == GestureFlags.Begin; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="GestureFlags"/> End is set.
|
||||
/// </summary>
|
||||
public bool End
|
||||
{
|
||||
get { return ((GestureFlags)flags & GestureFlags.End) == GestureFlags.End; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="GestureFlags"/> Inertia is set
|
||||
/// </summary>
|
||||
public bool Inertia
|
||||
{
|
||||
get { return ((GestureFlags)flags & GestureFlags.Inertia) == GestureFlags.Inertia; }
|
||||
}
|
||||
}
|
||||
}
|
||||
142
framework/MaterialSkin.Core/Gesture/UnmanagedLibrary.cs
Normal file
142
framework/MaterialSkin.Core/Gesture/UnmanagedLibrary.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
#region Copyright (c) Microsoft Corporation.
|
||||
//
|
||||
// The source code of UnmanagedLibrary.cs is quoted from Mike Stall's article:
|
||||
//
|
||||
// Type-safe Managed wrappers for kernel32!GetProcAddress
|
||||
// http://blogs.msdn.com/jmstall/archive/2007/01/06/Typesafe-GetProcAddress.aspx
|
||||
//
|
||||
// This source is subject to the Microsoft Public License.
|
||||
// See http://www.opensource.org/licenses/MS-PL.
|
||||
// All other rights reserved.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
#endregion
|
||||
|
||||
#region Using Directives
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Permissions;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace MaterialSkin.Gesture
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class to wrap an unmanaged DLL and be responsible for freeing it.
|
||||
/// </summary>
|
||||
/// <remarks>This is a managed wrapper over the native LoadLibrary, GetProcAddress, and
|
||||
/// FreeLibrary calls.
|
||||
/// </remarks>
|
||||
public sealed class UnmanagedLibrary : IDisposable
|
||||
{
|
||||
#region Safe Handles and Native imports
|
||||
|
||||
// See http://msdn.microsoft.com/msdnmag/issues/05/10/Reliability/ for more about safe handles.
|
||||
[SecurityPermission( SecurityAction.LinkDemand, UnmanagedCode = true )]
|
||||
sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeLibraryHandle() : base( true ) { }
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return NativeMethods.FreeLibrary( handle );
|
||||
}
|
||||
}
|
||||
|
||||
static class NativeMethods
|
||||
{
|
||||
const string KERNEL32 = "kernel32";
|
||||
[DllImport( KERNEL32, CharSet = CharSet.Auto, BestFitMapping = false, SetLastError = true )]
|
||||
public static extern SafeLibraryHandle LoadLibrary( string fileName );
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( KERNEL32, SetLastError = true )]
|
||||
[return: MarshalAs( UnmanagedType.Bool )]
|
||||
public static extern bool FreeLibrary( IntPtr hModule );
|
||||
|
||||
[DllImport( KERNEL32 )]
|
||||
public static extern IntPtr GetProcAddress( SafeLibraryHandle hModule, String procname );
|
||||
}
|
||||
|
||||
#endregion // Safe Handles and Native imports
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to load a dll and be responible for freeing it.
|
||||
/// </summary>
|
||||
/// <param name="fileName">full path name of dll to load</param>
|
||||
/// <exception cref="FileNotFoundException">if fileName can't be found</exception>
|
||||
/// <remarks>Throws exceptions on failure. Most common failure would be file-not-found, or
|
||||
/// that the file is not a loadable image.</remarks>
|
||||
public UnmanagedLibrary( string fileName )
|
||||
{
|
||||
m_hLibrary = NativeMethods.LoadLibrary( fileName );
|
||||
if ( m_hLibrary.IsInvalid )
|
||||
{
|
||||
int hr = Marshal.GetHRForLastWin32Error();
|
||||
Marshal.ThrowExceptionForHR( hr );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamically lookup a function in the dll via kernel32!GetProcAddress.
|
||||
/// </summary>
|
||||
/// <param name="functionName">raw name of the function in the export table.</param>
|
||||
/// <returns>null if function is not found. Else a delegate to the unmanaged function.
|
||||
/// </returns>
|
||||
/// <remarks>GetProcAddress results are valid as long as the dll is not yet unloaded. This
|
||||
/// is very very dangerous to use since you need to ensure that the dll is not unloaded
|
||||
/// until after you're done with any objects implemented by the dll. For example, if you
|
||||
/// get a delegate that then gets an IUnknown implemented by this dll,
|
||||
/// you can not dispose this library until that IUnknown is collected. Else, you may free
|
||||
/// the library and then the CLR may call release on that IUnknown and it will crash.</remarks>
|
||||
public TDelegate GetUnmanagedFunction<TDelegate>( string functionName ) where TDelegate : class
|
||||
{
|
||||
IntPtr p = NativeMethods.GetProcAddress( m_hLibrary, functionName );
|
||||
|
||||
// Failure is a common case, especially for adaptive code.
|
||||
if ( p == IntPtr.Zero )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Delegate function = Marshal.GetDelegateForFunctionPointer( p, typeof( TDelegate ) );
|
||||
|
||||
// Ideally, we'd just make the constraint on TDelegate be
|
||||
// System.Delegate, but compiler error CS0702 (constrained can't be System.Delegate)
|
||||
// prevents that. So we make the constraint system.object and do the cast from object-->TDelegate.
|
||||
object o = function;
|
||||
|
||||
return (TDelegate)o;
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
/// <summary>
|
||||
/// Call FreeLibrary on the unmanaged dll. All function pointers
|
||||
/// handed out from this class become invalid after this.
|
||||
/// </summary>
|
||||
/// <remarks>This is very dangerous because it suddenly invalidate
|
||||
/// everything retrieved from this dll. This includes any functions
|
||||
/// handed out via GetProcAddress, and potentially any objects returned
|
||||
/// from those functions (which may have an implemention in the
|
||||
/// dll).
|
||||
/// </remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
if ( !m_hLibrary.IsClosed )
|
||||
{
|
||||
m_hLibrary.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// Unmanaged resource. CLR will ensure SafeHandles get freed, without requiring a finalizer on this class.
|
||||
SafeLibraryHandle m_hLibrary;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user