// Pass in the device you want to connect to!
        public SignatureForm(wgssSTU.IUsbDevice usbDevice, bool encryptionWanted)
        {
            int currentPenDataOptionMode;

            m_penDataOptionMode = -1;

            // This is a DPI aware application, so ensure you understand how .NET client coordinates work.
            // Testing using a Windows installation set to a high DPI is recommended to understand how
            // values get scaled or not.

            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode       = System.Windows.Forms.AutoScaleMode.Dpi;

            InitializeComponent();

            m_penData = new List <wgssSTU.IPenData>();

            m_tablet = new wgssSTU.Tablet();
            wgssSTU.ProtocolHelper protocolHelper = new wgssSTU.ProtocolHelper();

            // A more sophisticated applications should cycle for a few times as the connection may only be
            // temporarily unavailable for a second or so.
            // For example, if a background process such as Wacom STU Display
            // is running, this periodically updates a slideshow of images to the device.

            wgssSTU.IErrorCode ec = m_tablet.usbConnect(usbDevice, true);
            if (ec.value == 0)
            {
                m_capability  = m_tablet.getCapability();
                m_information = m_tablet.getInformation();

                // First find out if the pad supports the pen data option mode (the 300 doesn't)
                currentPenDataOptionMode = getPenDataOptionMode();

                // Set up the tablet to return time stamp with the pen data or just basic data
                setPenDataOptionMode(currentPenDataOptionMode);
            }
            else
            {
                throw new Exception(ec.message);
            }

            this.SuspendLayout();
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode       = System.Windows.Forms.AutoScaleMode.Dpi;

            // Set the size of the client window to be actual size,
            // based on the reported DPI of the monitor.

            Size clientSize = new Size((int)(m_capability.tabletMaxX / 2540F * 96F), (int)(m_capability.tabletMaxY / 2540F * 96F));

            this.ClientSize = clientSize;
            this.ResumeLayout();

            m_btns = new Button[3];
            if (usbDevice.idProduct != 0x00a2)
            {
                // Place the buttons across the bottom of the screen.

                int w2 = m_capability.screenWidth / 3;
                int w3 = m_capability.screenWidth / 3;
                int w1 = m_capability.screenWidth - w2 - w3;
                int y  = m_capability.screenHeight * 6 / 7;
                int h  = m_capability.screenHeight - y;

                m_btns[0].Bounds = new Rectangle(0, y, w1, h);
                m_btns[1].Bounds = new Rectangle(w1, y, w2, h);
                m_btns[2].Bounds = new Rectangle(w1 + w2, y, w3, h);
            }
            else
            {
                // The STU-300 is very shallow, so it is better to utilise
                // the buttons to the side of the display instead.

                int x = m_capability.screenWidth * 3 / 4;
                int w = m_capability.screenWidth - x;

                int h2 = m_capability.screenHeight / 3;
                int h3 = m_capability.screenHeight / 3;
                int h1 = m_capability.screenHeight - h2 - h3;

                m_btns[0].Bounds = new Rectangle(x, 0, w, h1);
                m_btns[1].Bounds = new Rectangle(x, h1, w, h2);
                m_btns[2].Bounds = new Rectangle(x, h1 + h2, w, h3);
            }
            m_btns[0].Text  = "OK";
            m_btns[1].Text  = "Clear";
            m_btns[2].Text  = "Cancel";
            m_btns[0].Click = new EventHandler(btnOk_Click);
            m_btns[1].Click = new EventHandler(btnClear_Click);
            m_btns[2].Click = new EventHandler(btnCancel_Click);


            // Disable color if the STU-520 bulk driver isn't installed.
            // This isn't necessary, but uploading colour images with out the driver
            // is very slow.

            // Calculate the encodingMode that will be used to update the image
            ushort idP = m_tablet.getProductId();

            wgssSTU.encodingFlag encodingFlag = (wgssSTU.encodingFlag)protocolHelper.simulateEncodingFlag(idP, 0);
            bool useColor = false;

            if ((encodingFlag & (wgssSTU.encodingFlag.EncodingFlag_16bit | wgssSTU.encodingFlag.EncodingFlag_24bit)) != 0)
            {
                if (m_tablet.supportsWrite())
                {
                    useColor = true;
                }
            }
            if ((encodingFlag & wgssSTU.encodingFlag.EncodingFlag_24bit) != 0)
            {
                m_encodingMode = m_tablet.supportsWrite() ? wgssSTU.encodingMode.EncodingMode_24bit_Bulk : wgssSTU.encodingMode.EncodingMode_24bit;
            }
            else if ((encodingFlag & wgssSTU.encodingFlag.EncodingFlag_16bit) != 0)
            {
                m_encodingMode = m_tablet.supportsWrite() ? wgssSTU.encodingMode.EncodingMode_16bit_Bulk : wgssSTU.encodingMode.EncodingMode_16bit;
            }
            else
            {
                // assumes 1bit is available
                m_encodingMode = wgssSTU.encodingMode.EncodingMode_1bit;
            }

            // Size the bitmap to the size of the LCD screen.
            // This application uses the same bitmap for both the screen and client (window).
            // However, at high DPI, this bitmap will be stretch and it would be better to
            // create individual bitmaps for screen and client at native resolutions.
            m_bitmap = new Bitmap(m_capability.screenWidth, m_capability.screenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            {
                Graphics gfx = Graphics.FromImage(m_bitmap);
                gfx.Clear(Color.White);

                // Uses pixels for units as DPI won't be accurate for tablet LCD.
                Font         font = new Font(FontFamily.GenericSansSerif, m_btns[0].Bounds.Height / 2F, GraphicsUnit.Pixel);
                StringFormat sf   = new StringFormat();
                sf.Alignment     = StringAlignment.Center;
                sf.LineAlignment = StringAlignment.Center;

                if (useColor)
                {
                    gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
                }
                else
                {
                    // Anti-aliasing should be turned off for monochrome devices.
                    gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
                }

                // Draw the buttons
                for (int i = 0; i < m_btns.Length; ++i)
                {
                    if (useColor)
                    {
                        gfx.FillRectangle(Brushes.LightGray, m_btns[i].Bounds);
                    }
                    gfx.DrawRectangle(Pens.Black, m_btns[i].Bounds);
                    gfx.DrawString(m_btns[i].Text, font, Brushes.Black, m_btns[i].Bounds, sf);
                }

                gfx.Dispose();
                font.Dispose();

                // Finally, use this bitmap for the window background.
                this.BackgroundImage       = m_bitmap;
                this.BackgroundImageLayout = ImageLayout.Stretch;
            }

            // Now the bitmap has been created, it needs to be converted to device-native
            // format.
            {
                // Unfortunately it is not possible for the native COM component to
                // understand .NET bitmaps. We have therefore convert the .NET bitmap
                // into a memory blob that will be understood by COM.

                System.IO.MemoryStream stream = new System.IO.MemoryStream();
                m_bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                m_bitmapData   = (byte[])protocolHelper.resizeAndFlatten(stream.ToArray(), 0, 0, (uint)m_bitmap.Width, (uint)m_bitmap.Height, m_capability.screenWidth, m_capability.screenHeight, (byte)m_encodingMode, wgssSTU.Scale.Scale_Fit, 0, 0);
                protocolHelper = null;
                stream.Dispose();
            }

            // If you wish to further optimize image transfer, you can compress the image using
            // the Zlib algorithm.

            bool useZlibCompression = false;

            if (!useColor && useZlibCompression)
            {
                // m_bitmapData = compress_using_zlib(m_bitmapData); // insert compression here!
                m_encodingMode |= wgssSTU.encodingMode.EncodingMode_Zlib;
            }

            // Calculate the size and cache the inking pen.

            SizeF s          = this.AutoScaleDimensions;
            float inkWidthMM = 0.7F;

            m_penInk          = new Pen(Color.DarkBlue, inkWidthMM / 25.4F * ((s.Width + s.Height) / 2F));
            m_penInk.StartCap = m_penInk.EndCap = System.Drawing.Drawing2D.LineCap.Round;
            m_penInk.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;

            addDelegates();

            // Initialize the screen
            clearScreen();

            if (encryptionWanted)
            {
                if (m_tablet.isSupported((byte)wgssSTU.ReportId.ReportId_EncryptionStatus))
                {
                    MyEncryptionHandler2 e = new MyEncryptionHandler2();
                    m_tablet.encryptionHandler2 = e;
                    m_useEncryption             = true;
                }

                if (m_useEncryption)
                {
                    m_tablet.startCapture(0xc0ffee);
                }
            }

            // Enable the pen data on the screen (if not already)
            m_tablet.setInkingMode(0x01);
        }
        private bool connectB(bool repeat = false)
        {
            bool previousWarning = false;
            bool ret             = false; //return false means everything is OK, we have connected (if the tablet exists)

            if (dispatcherTimer.IsEnabled)
            {
                previousWarning = true;
                dispatcherTimer.Stop();
            }
            if (null != m_tablet)
            {
                if (!m_tablet.isConnected())
                {
                    wgssSTU.IErrorCode ec = null;
                    for (int n = 0; n < 5; n++)
                    {
                        try
                        {
                            ec = m_tablet.usbConnect(m_device, true);
                            if (ec != null && ec.value == 0)
                            {
                                n = 5;
                                break;
                            }
                            else if (ec != null && ec.value != 0 && n >= 4)
                            {
                                if (DebugInfo.IsDebuggerAttached())
                                {
                                    MessageBoxResult result = MessageBox.Show("Error connecting to a Pad. Error value: " + ec.value + " " + ec.message,
                                                                              "Confirmation", MessageBoxButton.OK, MessageBoxImage.Question);
                                }
                            }
                        }
                        catch (Exception)
                        {
                            if (ec != null && ec.value != 0 && n == 4) //ec.value == 32 means it's already being used by another program.
                            {
                                if (DebugInfo.IsDebuggerAttached())
                                {
                                    MessageBoxResult result = MessageBox.Show("Error connecting to a Pad. Error value: " + ec.value + " " + ec.message,
                                                                              "Confirmation", MessageBoxButton.OK, MessageBoxImage.Question);
                                }
                            }
                        }
                    }
                }

                if (!m_tablet.isConnected())
                {
                    ret = true; //We couldn't connect
                    if (repeat)
                    {
                        RemoveHandlers(dispatcherTimer);
                        dispatcherTimer.Tick += delegate { connectB(repeat); };
                        dispatcherTimer.Start();

                        if (!previousWarning)
                        {
                            SetWarning(true);
                        }
                    }
                }
                else
                {
                    if (previousWarning)
                    {
                        SetWarning(false);
                    }
                }
            }
            return(ret);
        }