Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'graphicsmode' into develop

  • Loading branch information...
commit 40ce2c42885382181f150c4508ee389213c737ad 2 parents 770b697 + 06a3d7e
@thefiddler thefiddler authored
View
12 Source/OpenTK/Graphics/GraphicsMode.cs
@@ -22,7 +22,6 @@ public class GraphicsMode : IEquatable<GraphicsMode>
IntPtr? index = null; // The id of the pixel format or visual.
static GraphicsMode defaultMode;
- static IGraphicsMode implementation;
static readonly object SyncRoot = new object();
#region Constructors
@@ -44,7 +43,7 @@ internal GraphicsMode(GraphicsMode mode)
{
if (depth < 0) throw new ArgumentOutOfRangeException("depth", "Must be greater than, or equal to zero.");
if (stencil < 0) throw new ArgumentOutOfRangeException("stencil", "Must be greater than, or equal to zero.");
- if (buffers <= 0) throw new ArgumentOutOfRangeException("buffers", "Must be greater than zero.");
+ if (buffers < 0) throw new ArgumentOutOfRangeException("buffers", "Must be greater than, or equal to zero.");
if (samples < 0) throw new ArgumentOutOfRangeException("samples", "Must be greater than, or equal to zero.");
this.Index = index;
@@ -255,7 +254,14 @@ public int Samples
{
return samples;
}
- private set { samples = value; }
+ private set
+ {
+ // Clamp antialiasing samples to max 64x
+ // This protects against a potential DOS during
+ // mode selection, when the user requests an
+ // abnormally high AA level.
+ samples = MathHelper.Clamp(value, 0, 64);
+ }
}
#endregion
View
56 Source/OpenTK/Platform/MacOS/AglContext.cs
@@ -52,8 +52,6 @@ class AglContext : DesktopGraphicsContext
DisplayDevice device;
bool mIsFullscreen = false;
- readonly MacOSGraphicsMode ModeSelector = new MacOSGraphicsMode();
-
public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext)
{
Debug.Print("Context Type: {0}", shareContext);
@@ -103,6 +101,7 @@ private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pi
aglAttributes.Add((int)pixelFormatAttribute);
aglAttributes.Add(value);
}
+
void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow, IntPtr shareContextRef, bool fullscreen)
{
Debug.Print("AGL pixel format attributes:");
@@ -110,51 +109,30 @@ void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow, IntPtr shar
AGLPixelFormat myAGLPixelFormat;
// Choose a pixel format with the attributes we specified.
- if (fullscreen)
- {
- IntPtr gdevice;
- IntPtr cgdevice = GetQuartzDevice(carbonWindow);
-
- if (cgdevice == IntPtr.Zero)
- cgdevice = (IntPtr)DisplayDevice.Default.Id;
+ IntPtr gdevice;
+ IntPtr cgdevice = GetQuartzDevice(carbonWindow);
- OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false);
+ if (cgdevice == IntPtr.Zero)
+ cgdevice = (IntPtr)DisplayDevice.Default.Id;
- if (status != OSStatus.NoError)
- throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
+ OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false);
- myAGLPixelFormat = ModeSelector.SelectPixelFormat(
- mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
- mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
- true, gdevice);
-
- Agl.AglError err = Agl.GetError();
- if (myAGLPixelFormat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat)
- {
- Debug.Print("Failed to create full screen pixel format.");
- Debug.Print("Trying again to create a non-fullscreen pixel format.");
-
- CreateContext(mode, carbonWindow, shareContextRef, false);
- return;
- }
- }
- else
- {
- myAGLPixelFormat = ModeSelector.SelectPixelFormat(
- mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
- mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
- false, IntPtr.Zero);
- MyAGLReportError("aglChoosePixelFormat");
- }
-
+ if (status != OSStatus.NoError)
+ throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
+
+ IGraphicsMode selector = new MacOSGraphicsMode(gdevice);
+ Mode = selector.SelectGraphicsMode(
+ mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
+ mode.AccumulatorFormat, mode.Buffers, mode.Stereo);
+ MyAGLReportError("aglChoosePixelFormat");
+
Debug.Print("Creating AGL context. Sharing with {0}", shareContextRef);
-
+ myAGLPixelFormat = Mode.Index.Value;
+
// create the context and share it with the share reference.
Handle = new ContextHandle(Agl.aglCreateContext(myAGLPixelFormat, shareContextRef));
MyAGLReportError("aglCreateContext");
- Mode = ModeSelector.GetGraphicsModeFromPixelFormat(myAGLPixelFormat);
-
// Free the pixel format from memory.
Agl.aglDestroyPixelFormat(myAGLPixelFormat);
MyAGLReportError("aglDestroyPixelFormat");
View
43 Source/OpenTK/Platform/MacOS/MacOSGraphicsMode.cs
@@ -37,14 +37,47 @@ namespace OpenTK.Platform.MacOS
class MacOSGraphicsMode : IGraphicsMode
{
+ readonly IntPtr Device;
+
+ public MacOSGraphicsMode(IntPtr device)
+ {
+ Device = device;
+ }
+
#region IGraphicsMode Members
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil,
int samples, ColorFormat accum, int buffers, bool stereo)
{
- IntPtr pixelformat = SelectPixelFormat(
- color, depth, stencil, samples, accum, buffers, stereo,
- false, IntPtr.Zero);
+ IntPtr pixelformat;
+ do
+ {
+ pixelformat = SelectPixelFormat(
+ color, depth, stencil, samples, accum, buffers, stereo,
+ true, Device);
+
+ Agl.AglError err = Agl.GetError();
+ if (pixelformat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat)
+ {
+ Debug.Print("Failed to create full screen pixel format.");
+ Debug.Print("Trying again to create a non-fullscreen pixel format.");
+ pixelformat = SelectPixelFormat(
+ color, depth, stencil, samples, accum, buffers, stereo,
+ false, IntPtr.Zero);
+ }
+
+ if (pixelformat == IntPtr.Zero)
+ {
+ if (!Utilities.RelaxGraphicsMode(
+ ref color, ref depth, ref stencil, ref samples, ref accum,
+ ref buffers, ref stereo))
+ {
+ throw new GraphicsModeException("Requested GraphicsMode not available.");
+ }
+ }
+ }
+ while (pixelformat == IntPtr.Zero);
+
return GetGraphicsModeFromPixelFormat(pixelformat);
}
@@ -52,7 +85,7 @@ class MacOSGraphicsMode : IGraphicsMode
#region Internal Members
- internal GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
+ GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
{
int r, g, b, a;
Agl.aglDescribePixelFormat(pixelformat, Agl.PixelFormatAttribute.AGL_RED_SIZE, out r);
@@ -75,7 +108,7 @@ internal GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
depth, stencil, samples, new ColorFormat(ar, ag, ab, aa), buffers + 1, stereo != 0);
}
- internal IntPtr SelectPixelFormat(ColorFormat color, int depth, int stencil, int samples,
+ IntPtr SelectPixelFormat(ColorFormat color, int depth, int stencil, int samples,
ColorFormat accum, int buffers, bool stereo, bool fullscreen, IntPtr device)
{
List<int> attribs = new List<int>();
View
41 Source/OpenTK/Platform/SDL2/Sdl2GraphicsContext.cs
@@ -63,8 +63,20 @@ class Sdl2GraphicsContext : DesktopGraphicsContext
{
lock (SDL.Sync)
{
- SetGLAttributes(mode, shareContext, major, minor, flags);
- SdlContext = new ContextHandle(SDL.GL.CreateContext(Window.Handle));
+ bool retry = false;
+ do
+ {
+ SetGLAttributes(mode, shareContext, major, minor, flags);
+ SdlContext = new ContextHandle(SDL.GL.CreateContext(Window.Handle));
+
+ // If we failed to create a valid context, relax the GraphicsMode
+ // and try again.
+ retry =
+ SdlContext == ContextHandle.Zero &&
+ Utilities.RelaxGraphicsMode(ref mode);
+ }
+ while (retry);
+
if (SdlContext == ContextHandle.Zero)
{
var error = SDL.GetError();
@@ -152,12 +164,37 @@ static GraphicsMode GetGLAttributes(ContextHandle sdlContext, out GraphicsContex
stereo != 0 ? true : false);
}
+ static void ClearGLAttributes()
+ {
+ SDL.GL.SetAttribute(ContextAttribute.ACCUM_ALPHA_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.ACCUM_RED_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.ACCUM_GREEN_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.ACCUM_BLUE_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.DOUBLEBUFFER, 0);
+ SDL.GL.SetAttribute(ContextAttribute.ALPHA_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.RED_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.GREEN_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.BLUE_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.DEPTH_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.MULTISAMPLEBUFFERS, 0);
+ SDL.GL.SetAttribute(ContextAttribute.MULTISAMPLESAMPLES, 0);
+ SDL.GL.SetAttribute(ContextAttribute.STENCIL_SIZE, 0);
+ SDL.GL.SetAttribute(ContextAttribute.STEREO, 0);
+ SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MAJOR_VERSION, 1);
+ SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MINOR_VERSION, 0);
+ SDL.GL.SetAttribute(ContextAttribute.CONTEXT_FLAGS, 0);
+ SDL.GL.SetAttribute(ContextAttribute.CONTEXT_EGL, 0);
+ SDL.GL.SetAttribute(ContextAttribute.CONTEXT_PROFILE_MASK, 0);
+ SDL.GL.SetAttribute(ContextAttribute.SHARE_WITH_CURRENT_CONTEXT, 0);
+ }
+
static void SetGLAttributes(GraphicsMode mode,
IGraphicsContext shareContext,
int major, int minor,
GraphicsContextFlags flags)
{
ContextProfileFlags cpflags = 0;
+ ClearGLAttributes();
if (mode.AccumulatorFormat.BitsPerPixel > 0)
{
View
108 Source/OpenTK/Platform/Utilities.cs
@@ -307,5 +307,113 @@ public static IWindowInfo CreateSdl2WindowInfo(IntPtr windowHandle)
#endregion
#endregion
+
+ #region RelaxGraphicsMode
+
+ internal static bool RelaxGraphicsMode(ref GraphicsMode mode)
+ {
+ ColorFormat color = mode.ColorFormat;
+ int depth = mode.Depth;
+ int stencil = mode.Stencil;
+ int samples = mode.Samples;
+ ColorFormat accum = mode.AccumulatorFormat;
+ int buffers = mode.Buffers;
+ bool stereo = mode.Stereo;
+
+ bool success = RelaxGraphicsMode(
+ ref color, ref depth, ref stencil, ref samples,
+ ref accum, ref buffers, ref stereo);
+
+ mode = new GraphicsMode(
+ color, depth, stencil, samples,
+ accum, buffers, stereo);
+
+ return success;
+ }
+
+ /// \internal
+ /// <summary>
+ /// Relaxes graphics mode parameters. Use this function to increase compatibility
+ /// on systems that do not directly support a requested GraphicsMode. For example:
+ /// - user requested stereoscopic rendering, but GPU does not support stereo
+ /// - user requseted 16x antialiasing, but GPU only supports 4x
+ /// </summary>
+ /// <returns><c>true</c>, if a graphics mode parameter was relaxed, <c>false</c> otherwise.</returns>
+ /// <param name="color">Color bits.</param>
+ /// <param name="depth">Depth bits.</param>
+ /// <param name="stencil">Stencil bits.</param>
+ /// <param name="samples">Number of antialiasing samples.</param>
+ /// <param name="accum">Accumulator buffer bits.</param>
+ /// <param name="buffers">Number of rendering buffers (1 for single buffering, 2+ for double buffering, 0 for don't care).</param>
+ /// <param name="stereo">Stereoscopic rendering enabled/disabled.</param>
+ internal static bool RelaxGraphicsMode(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, ref ColorFormat accum, ref int buffers, ref bool stereo)
+ {
+ // Parameters are relaxed in order of importance.
+ // - Accumulator buffers are way outdated as a concept,
+ // so they go first.
+ // - Triple+ buffering is generally not supported by the
+ // core WGL/GLX/AGL/CGL/EGL specs, so we clamp
+ // to double-buffering as a second step. (If this doesn't help
+ // we will also fall back to undefined single/double buffering
+ // as a last resort).
+ // - AA samples are an easy way to increase compatibility
+ // so they go next.
+ // - Stereoscopic is only supported on very few GPUs
+ // (Quadro/FirePro series) so it goes next.
+ // - The rest of the parameters then follow.
+
+ if (accum != 0)
+ {
+ accum = 0;
+ return true;
+ }
+
+ if (buffers > 2)
+ {
+ buffers = 2;
+ return true;
+ }
+
+ if (samples > 0)
+ {
+ samples = Math.Max(samples - 1, 0);
+ return true;
+ }
+
+ if (stereo)
+ {
+ stereo = false;
+ return true;
+ }
+
+ if (stencil != 0)
+ {
+ stencil = 0;
+ return true;
+ }
+
+ if (depth != 0)
+ {
+ depth = 0;
+ return true;
+ }
+
+ if (color != 24)
+ {
+ color = 24;
+ return true;
+ }
+
+ if (buffers != 0)
+ {
+ buffers = 0;
+ return true;
+ }
+
+ // no parameters left to relax, fail
+ return false;
+ }
+
+ #endregion
}
}
View
203 Source/OpenTK/Platform/Windows/WinGraphicsMode.cs
@@ -96,114 +96,123 @@ public WinGraphicsMode(IntPtr device)
// hardware acceleration (e.g. we are running in a VM or in a remote desktop
// connection), this method will return 0 formats and we will fall back to
// ChoosePixelFormatPFD.
- GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode)
+ GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode desired_mode)
{
GraphicsMode created_mode = null;
+ GraphicsMode mode = new GraphicsMode(desired_mode);
if (Wgl.SupportsExtension("WGL_ARB_pixel_format") &&
Wgl.SupportsFunction("wglChoosePixelFormatARB"))
{
+ int[] format = new int[1];
+ int count;
List<int> attributes = new List<int>();
- attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
- attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb);
-
- attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb);
- attributes.Add(1);
+ bool retry = false;
- if (mode.ColorFormat.Red > 0)
+ do
{
- attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb);
- attributes.Add(mode.ColorFormat.Red);
- }
-
- if (mode.ColorFormat.Green > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb);
- attributes.Add(mode.ColorFormat.Green);
- }
-
- if (mode.ColorFormat.Blue > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb);
- attributes.Add(mode.ColorFormat.Blue);
- }
-
- if (mode.ColorFormat.Alpha > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb);
- attributes.Add(mode.ColorFormat.Alpha);
- }
-
- if (mode.Depth > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb);
- attributes.Add(mode.Depth);
- }
-
- if (mode.Stencil > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb);
- attributes.Add(mode.Stencil);
- }
-
- if (mode.AccumulatorFormat.Red > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb);
- attributes.Add(mode.AccumulatorFormat.Red);
- }
-
- if (mode.AccumulatorFormat.Green > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb);
- attributes.Add(mode.AccumulatorFormat.Green);
- }
-
- if (mode.AccumulatorFormat.Blue > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb);
- attributes.Add(mode.AccumulatorFormat.Blue);
- }
-
- if (mode.AccumulatorFormat.Alpha > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb);
- attributes.Add(mode.AccumulatorFormat.Alpha);
- }
-
- if (mode.Samples > 0 &&
- Wgl.SupportsExtension("WGL_ARB_multisample"))
- {
- attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb);
- attributes.Add(1);
- attributes.Add((int)WGL_ARB_multisample.SamplesArb);
- attributes.Add(mode.Samples);
- }
-
- if (mode.Buffers > 0)
- {
- attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb);
- attributes.Add(mode.Buffers > 1 ? 1 : 0);
- }
-
- if (mode.Stereo)
- {
- attributes.Add((int)WGL_ARB_pixel_format.StereoArb);
+ attributes.Clear();
+ attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
+ attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb);
+ attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb);
attributes.Add(1);
- }
-
- attributes.Add(0);
- attributes.Add(0);
- int[] format = new int[1];
- int count;
- if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)
- && count > 0)
- {
- created_mode = DescribePixelFormatARB(device, format[0]);
- }
- else
- {
- Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error());
+ if (mode.ColorFormat.Red > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb);
+ attributes.Add(mode.ColorFormat.Red);
+ }
+
+ if (mode.ColorFormat.Green > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb);
+ attributes.Add(mode.ColorFormat.Green);
+ }
+
+ if (mode.ColorFormat.Blue > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb);
+ attributes.Add(mode.ColorFormat.Blue);
+ }
+
+ if (mode.ColorFormat.Alpha > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb);
+ attributes.Add(mode.ColorFormat.Alpha);
+ }
+
+ if (mode.Depth > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb);
+ attributes.Add(mode.Depth);
+ }
+
+ if (mode.Stencil > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb);
+ attributes.Add(mode.Stencil);
+ }
+
+ if (mode.AccumulatorFormat.Red > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb);
+ attributes.Add(mode.AccumulatorFormat.Red);
+ }
+
+ if (mode.AccumulatorFormat.Green > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb);
+ attributes.Add(mode.AccumulatorFormat.Green);
+ }
+
+ if (mode.AccumulatorFormat.Blue > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb);
+ attributes.Add(mode.AccumulatorFormat.Blue);
+ }
+
+ if (mode.AccumulatorFormat.Alpha > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb);
+ attributes.Add(mode.AccumulatorFormat.Alpha);
+ }
+
+ if (mode.Samples > 0 &&
+ Wgl.SupportsExtension("WGL_ARB_multisample"))
+ {
+ attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb);
+ attributes.Add(1);
+ attributes.Add((int)WGL_ARB_multisample.SamplesArb);
+ attributes.Add(mode.Samples);
+ }
+
+ if (mode.Buffers > 0)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb);
+ attributes.Add(mode.Buffers > 1 ? 1 : 0);
+ }
+
+ if (mode.Stereo)
+ {
+ attributes.Add((int)WGL_ARB_pixel_format.StereoArb);
+ attributes.Add(1);
+ }
+
+ attributes.Add(0);
+ attributes.Add(0);
+
+ if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)
+ && count > 0)
+ {
+ created_mode = DescribePixelFormatARB(device, format[0]);
+ retry = false;
+ }
+ else
+ {
+ Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error());
+ retry = Utilities.RelaxGraphicsMode(ref mode);
+ }
}
+ while (retry);
}
else
{
View
45 Source/OpenTK/Platform/X11/X11GraphicsMode.cs
@@ -52,49 +52,8 @@ public X11GraphicsMode()
if (visual == IntPtr.Zero)
{
// Relax parameters and retry
- if (stereo)
- {
- stereo = false;
- continue;
- }
-
- if (accum != 0)
- {
- accum = 0;
- continue;
- }
-
- if (samples > 0)
- {
- samples = Math.Max(samples - 2, 0);
- continue;
- }
-
- if (stencil != 0)
- {
- stencil = 0;
- continue;
- }
-
- if (depth != 0)
- {
- depth = 0;
- continue;
- }
-
- if (color != 24)
- {
- color = 24;
- continue;
- }
-
- if (buffers != 0)
- {
- buffers = 0;
- continue;
- }
-
- throw new GraphicsModeException("Requested GraphicsMode not available.");
+ if (!Utilities.RelaxGraphicsMode(ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref stereo))
+ throw new GraphicsModeException("Requested GraphicsMode not available.");
}
}
while (visual == IntPtr.Zero);
Please sign in to comment.
Something went wrong with that request. Please try again.