从WIn32.dll调用函数时Winform无效句柄错误

时间:2018-03-24 05:16:46

标签: c# winforms clipboard handle user32

我正在构建一个需要剪贴板功能的Winform应用程序,因此我需要调用user32.dll。现在,当我启动应用程序时,我收到以下错误System.UnauthorizedAccessException: 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))'

经过进一步调查后发现,当我尝试使用SetClipboardViewer()注册clipBoardViewer时,我从user32.dll获得了invalid Handle错误代码。

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";
            }
        }

int error = Marshal.GetLastWin32Error();行返回错误代码1400,窗口句柄无效see this

可能的解决方案

我已经确认线程公寓已正确设置

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

我也尝试使用GC.KeepAlive()所以它不会收集表单或它的句柄,但我真的不明白为什么会这样。

当我调试应用程序时,我发现,在调用SetClipBoardViewer()之前,表单句柄有一个值(我认为)是有效的,至少它不是null或{{1}所以我不明白为什么句柄会被视为无效。

注意

  • 应用程序之前在同一台计算机上编译过,我只是 暂时没有工作,现在它不起作用。
  • 完整的应用程序在其当前状态下可用on GitHub at this commit(减去我为调试目的添加的几行以及一些注释,以帮助您理解这一点)。

1 个答案:

答案 0 :(得分:0)

我发现了错误source code from GIT。更改应用程序设置。

转到Properties - &gt; Security并更改为&#39;这是一个完全信任的应用程序&#39;。

更改后,应用程序启动没有问题,剪贴板功能正常工作。