低权限模式可以用STA模式吗?

使用问题 · 43 次浏览
FaniX 创建于 8天19小时前

我想在Quicker里创建一个接受拖放的窗口,用于快速处理文件。由于Quicker运行在高权限态,普通窗口无法接受拖放。

我尝试创建一个低权限的Winform窗口用来接受拖放文件,但是Winform需要STA线程来允许拖放。能否允许低权限模式也通过其他线程方式运行?

示例:

using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Windows.Forms;

public class MainForm : Form
{
    public ListBox listBoxFiles;
    public List<string> listFiles = new List<string>();

    public MainForm()
    {
        Text = "请将文件拖入此窗口";
        Size = new System.Drawing.Size(500, 300);
        listBoxFiles = new ListBox { Dock = DockStyle.Fill };
        Controls.Add(listBoxFiles);
        AllowDrop = true;
        DragEnter += MainForm_DragEnter;
        DragDrop += MainForm_DragDrop;
    }

    private void MainForm_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormats.FileDrop))
        {
            e.Effect = DragDropEffects.Copy;
        }
        else
        {
            e.Effect = DragDropEffects.None;
        }
    }

    private void MainForm_DragDrop(object sender, DragEventArgs e)
    {
        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
        if (files != null && files.Length > 0)
        {
            listBoxFiles.Items.Clear();
            listFiles.Clear();
            foreach (string file in files)
            {
                listBoxFiles.Items.Add(file);
                listFiles.Add(file);
            }
        }
    }
}

public static string Exec(string paramValue)
{
    using(MainForm f = new MainForm()){
        f.ShowDialog();
        return string.Join("\n",f.listFiles);
    };
}

直接运行会提示

System.InvalidOperationException: DragDrop 注册失败。
System.Threading.ThreadStateException: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。
   在 System.Windows.Forms.Control.SetAcceptDrops(Boolean accept)
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Windows.Forms.Control.SetAcceptDrops(Boolean accept)
   在 System.Windows.Forms.Control.OnHandleCreated(EventArgs e)
   在 System.Windows.Forms.Form.OnHandleCreated(EventArgs e)
   在 System.Windows.Forms.Control.WmCreate(Message& m)
   在 System.Windows.Forms.Control.WndProc(Message& m)
   在 System.Windows.Forms.Form.WmCreate(Message& m)
   在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
FaniX 最后更新于 2026/4/21

回复内容
CL 8天19小时前
#1

可以试试创建一个新的线程。AI给的参考代码:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

public class MainForm : Form
{
    public ListBox listBoxFiles;
    public List<string> listFiles { get; } = new List<string>();

    public MainForm()
    {
        Text = "请将文件拖入此窗口";
        Size = new System.Drawing.Size(500, 300);

        listBoxFiles = new ListBox { Dock = DockStyle.Fill };
        Controls.Add(listBoxFiles);

        AllowDrop = true;
        DragEnter += MainForm_DragEnter;
        DragDrop += MainForm_DragDrop;
    }

    private void MainForm_DragEnter(object sender, DragEventArgs e)
    {
        e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
            ? DragDropEffects.Copy
            : DragDropEffects.None;
    }

    private void MainForm_DragDrop(object sender, DragEventArgs e)
    {
        if (e.Data.GetData(DataFormats.FileDrop) is string[] files)
        {
            listBoxFiles.Items.Clear();
            listFiles.Clear();

            foreach (var file in files)
            {
                listBoxFiles.Items.Add(file);
                listFiles.Add(file);
            }
        }
    }
}

public static class Runner
{
    public static string Exec()
    {
        string result = "";
        Exception threadEx = null;

        var t = new Thread(() =>
        {
            try
            {
                using var f = new MainForm();
                if (f.ShowDialog() == DialogResult.OK || f.listFiles.Count > 0)
                {
                    result = string.Join("\n", f.listFiles);
                }
            }
            catch (Exception ex)
            {
                threadEx = ex;
            }
        });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();

        if (threadEx != null)
            throw threadEx;

        return result;
    }
}
FaniX 回复 CL 8天10小时前 :

设置启用线程可以实现功能。我的窗口需要等待用户关闭,但是可能需要等待很久,可以允许将 最长等待时间(ms) 设为0以取消等待超时吗?

CL 回复 FaniX 8天1小时前 :

设置一个大的数字,现在会提前停止么? 

FaniX 回复 CL 7天23小时前 :

$=int.MaxValue倒是也行,只是希望最好能从逻辑上就避免这方面的问题

回复主贴