Winform Invalid Handle Error when calling function from WIn32.dll

0

I am building a Winform application that requires Clipboard fonctions hence I need to make calls to user32.dll . Now, whenevr I launched the application, I got the following error System.UnauthorizedAccessException: 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))'.

After further investigation, it turns out that when I attempt to register the clipBoardViewer using SetClipboardViewer(), I get an invalid Handle error code from user32.dll .

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;

namespace NiceClip
{
    public partial class MainForm : Form
    {
        [DllImport("User32.dll")]
        protected static extern int SetClipboardViewer(int hWndNewViewer);
        [DllImport("User32.dll")]
        protected static extern int GetLastError();
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        IntPtr nextClipboardViewer;
        NotifyIcon niceClipIcon;
        Icon niceClipIconImage;
        ContextMenu contextMenu = new ContextMenu();

        bool reallyQuit = false;
        bool isCopying = false;

        public MainForm()
        {
            InitializeComponent();
            nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);

            if (this.clipboardHistoryList.Items.Count > 0)
                this.clipboardHistoryList.SetSelected(0, true);
            clipboardHistoryList.Select();

            this.TopMost = true;

            niceClipIconImage = Properties.Resources.clipboard;
            niceClipIcon = new NotifyIcon
            {
                Icon = niceClipIconImage,
                Visible = true
            };

            MenuItem quitMenuItem = new MenuItem("Quit");
            MenuItem showFormItem = new MenuItem("NiceClip");
            this.contextMenu.MenuItems.Add(showFormItem);
            this.contextMenu.MenuItems.Add("-");
            this.contextMenu.MenuItems.Add(quitMenuItem);

            niceClipIcon.ContextMenu = contextMenu;

            quitMenuItem.Click += QuitMenuItem_Click;
            showFormItem.Click += ShowForm;
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
        }

        /// <summary>
        /// Takes care of the external DLL calls to user32 to receive notification when
        /// the clipboard is modified. Passes along notifications to any other process that
        /// is subscribed to the event notification chain.
        /// </summary>
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;

            int error = Marshal.GetLastWin32Error(); // Error is code 1400 (invalid window handle)

            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    if (!isCopying)
                        AddClipBoardEntry();
                    break;
                case WM_CHANGECBCHAIN:
                    if (m.WParam == nextClipboardViewer)
                        nextClipboardViewer = m.LParam;
                    else
                        SendMessage(nextClipboardViewer, m.Msg, m.WParam,
                                    m.LParam);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        /// <summary>
        /// Adds a clipboard history to the clipboard history list.
        /// </summary>
        private void AddClipBoardEntry()
        {
            if (Clipboard.ContainsText()) // FAILS HERE
            {
                string clipboardText = Clipboard.GetText();
                if (!String.IsNullOrEmpty(clipboardText))
                {
                    clipboardHistoryList.Items.Insert(0, clipboardText);
                    toolStripStatusLabel.Text = "Entry added in the clipboard history.";
                    deleteButton.Enabled = true;
                }
            }
            else
            {
                toolStripStatusLabel.Text = "History entry was not added because it was null or empty";
            }
        }

THe line int error = Marshal.GetLastWin32Error(); returns error code 1400 which is Invalid window handle, see this.

Possible Solutions

I have verified that the thread apartment is correctly set

namespace NiceClip
{
    static class Program
    {
        [STAThread]        // Here
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

I also tried to use GC.KeepAlive() so it wouldn't collect the form or it's handle but I really don't understand why it would.

When I debug the application, I observe that, RIGHT BEFORE calling SetClipBoardViewer(), the form handle has a value (that I think) is valid, at least it's not null or 0x0000so I don't understand why the handle would be deemed as invalid.

Note

  • The application has compiled before on the same computer, I just haven't worked on it for a while and now it doesn't work.
  • The full application is available on GitHub at this commit in it's current state (minus a few lines I added for debugging purposes and some comments to help you guys make sense out of this).
c#
winforms
clipboard
handle
user32
asked on Stack Overflow Mar 24, 2018 by Gaboik1 • edited Mar 24, 2018 by Gaboik1

1 Answer

0

I found the error (source code from GIT). Change the application setting.

Go to Properties --> Security and change to 'This is a Full trust application'.

After this change the application starts without a problem and the clipboard functions work correctly.

answered on Stack Overflow Mar 24, 2018 by Julo

User contributions licensed under CC BY-SA 3.0