首页 新闻 会员 周边

winform多线程牛人进.....

0
悬赏园豆:20 [已解决问题] 解决于 2013-04-14 12:43

为什么要加上tr.SetApartmentState(ApartmentState.STA);这句。否则会报下面那个错!

请详细回答!

using System;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        private Thread tr;
        void Form1_Load(object sender, EventArgs e)
        {
            tr = new Thread(new ThreadStart(Do));
            tr.SetApartmentState(ApartmentState.STA);
            tr.IsBackground = true;
            tr.Start();
        }

        private void Do()
        {
            System.Windows.Forms.SaveFileDialog s = new SaveFileDialog();
            if (s.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                MessageBox.Show("123");
            }
            //在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。
            //请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
        }
    }
}

KeVinDurant的主页 KeVinDurant | 初学一级 | 园豆:5
提问于:2013-03-18 16:57
< >
分享
最佳答案
-2

private void Do()        

        {         

this.Invoke(new MethodInvoker(delegate
{

System.Windows.Forms.SaveFileDialog s = new SaveFileDialog();
            if (s.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                MessageBox.Show("123");
            }

}));

}

你可以不要tr.SetApartmentState(ApartmentState.STA);  试试我这写的,主要是跨线程的原因吧。

收获园豆:20
悟行 | 专家六级 |园豆:12559 | 2013-03-30 19:14
其他回答(2)
0

多线程访问了控件就会出现这个问题,

请使用BeginInvoke或Invoke方法

只会造轮子 | 园豆:2274 (老鸟四级) | 2013-03-18 18:24

你换成System.Windows.Forms.TextBox t = new TextBox();就不会啦。。根本性不是这个原因...

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-18 22:58
0

这是你所要访问的第三方组件就是“单线程单元模型”。所以你访问他你的线程也应该是单线程单元模式

滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-18 19:03

能否说详细点

System.Windows.Forms.SaveFileDialog s = new SaveFileDialog();这个控件是系统自带的。不是第三方哦。。。

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-18 22:59

@KeVinDurant: 

什么是OLE:http://zhidao.baidu.com/question/5347035.html

System.Windows.Forms.SaveFileDialog s = new SaveFileDialog();
System.Diagnostics.Debug.Write(s.ShowDialog().ToString());

我看了下问题是出在ShowDialog()上面,用reflector看内部代码是:

[SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected abstract bool RunDialog(IntPtr hwndOwner);
调用Win32内部方法,该方法肯定访问了现成的OLE组件,且这个组件是以SAT模型公开的...


调用SAT的COM(即OLE调用),只能用对应的单元线程模型调用,这也是处于安全性考虑。

详见:http://support.microsoft.com/kb/150777/zh-cn    (中文可能翻译的不好,可以找原文看看)

COM 中的线程模型为使用不同线程结构的组件提供一起工作的机制。同时还为需要它们的组件提供同步服务。例如,某个特定对象可能被设计成只能由单线程调用, 并且可能无法同步来自客户的并行调用。如果这种对象被多个线程同时调用,则将导致系统崩溃或产生错误。COM 提供处理这种线程结构互操作性的机制。 

选择线程模型
组件可以选择支持 STA 模型、MTA 模型或使用混合线程模型支持这两种模型的组合。例如,执行大量 I/O 的对象可以选择支持 MTA,这样便可通过允许在 I/O 等待时间内进行接口调用,为客户提供最大程度的响应。或者,与用户相互作用的对象几乎总是选择支持 STA,以便用其 GUI 操作同步传入的 COM 调用。由于 COM 提供同步,因此支持 STA 模型比较容易。由于对象必须实现同步,因此支持 MTA 模型比较困难,但因为同步只是用于小部分代码,而不是用于由 COM 所提供的整个接口调用,所以到客户的响应较好。

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 00:28

@滴答的雨: 用reflector看内部代码是??这句话什么意思?怎么操作。。??

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 10:09

@KeVinDurant: reflector.exe可以看到.NET封装的一些底层代码

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 10:10

@滴答的雨: 调用Win32内部方法,该方法肯定访问了现成的OLE组件,且这个组件是以SAT模型公开的...

 

这句怎么解释。。从哪里可以看出来?

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 10:19

@KeVinDurant: 推测。因为这种对话框本身就可能是之前留下来的组件啊,不会说每个组件都C#重新开发一次。喜欢研究的话把clr源码下下来研究下

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 10:27

@滴答的雨: 怎么看出来是不是用c#开发的...还是用的其它组件??怎么查看?

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 10:33

@KeVinDurant: reflector.exe能看到的就是C#开发的,当你发现这工具看不到的函数就是其他语言开发的

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 10:35

@滴答的雨: 

[SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public abstract void Reset();
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected abstract bool RunDialog(IntPtr hwndOwner);
        public DialogResult ShowDialog()
        {
            return this.ShowDialog(null);
        }
        
        public DialogResult ShowDialog(IWin32Window owner)
        {
            System.Windows.Forms.IntSecurity.SafeSubWindows.Demand();
            if (!SystemInformation.UserInteractive)
            {
                throw new InvalidOperationException(System.Windows.Forms.SR.GetString("CantShowModalOnNonInteractive"));
            }
            NativeWindow window = null;
            IntPtr zero = IntPtr.Zero;
            DialogResult cancel = DialogResult.Cancel;
            try
            {
                if (owner != null)
                {
                    zero = Control.GetSafeHandle(owner);
                }
                if (zero == IntPtr.Zero)
                {
                    zero = System.Windows.Forms.UnsafeNativeMethods.GetActiveWindow();
                }
                if (zero == IntPtr.Zero)
                {
                    window = new NativeWindow();
                    window.CreateHandle(new CreateParams());
                    zero = window.Handle;
                }
                if (helpMsg == 0)
                {
                    helpMsg = System.Windows.Forms.SafeNativeMethods.RegisterWindowMessage("commdlg_help");
                }
                System.Windows.Forms.NativeMethods.WndProc d = new System.Windows.Forms.NativeMethods.WndProc(this.OwnerWndProc);
                this.hookedWndProc = Marshal.GetFunctionPointerForDelegate(d);
                IntPtr userCookie = IntPtr.Zero;
                try
                {
                    this.defOwnerWndProc = System.Windows.Forms.UnsafeNativeMethods.SetWindowLong(new HandleRef(this, zero), -4, d);
                    if (Application.UseVisualStyles)
                    {
                        userCookie = System.Windows.Forms.UnsafeNativeMethods.ThemingScope.Activate();
                    }
                    Application.BeginModalMessageLoop();
                    try
                    {
                        cancel = this.RunDialog(zero) ? DialogResult.OK : DialogResult.Cancel;
                    }
                    finally
                    {
                        Application.EndModalMessageLoop();
                    }
                    return cancel;
                }
                finally
                {
                    IntPtr windowLong = System.Windows.Forms.UnsafeNativeMethods.GetWindowLong(new HandleRef(this, zero), -4);
                    if ((IntPtr.Zero != this.defOwnerWndProc) || (windowLong != this.hookedWndProc))
                    {
                        System.Windows.Forms.UnsafeNativeMethods.SetWindowLong(new HandleRef(this, zero), -4, new HandleRef(this, this.defOwnerWndProc));
                    }
                    System.Windows.Forms.UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
                    this.defOwnerWndProc = IntPtr.Zero;
                    this.hookedWndProc = IntPtr.Zero;
                    GC.KeepAlive(d);
                }
            }
            finally
            {
                if (window != null)
                {
                    window.DestroyHandle();
                }
            }
            return cancel;
        }刚反编译了。从这段代码怎么看出调用了win32 API? OLE?

SAT模型公开?
支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 10:49

@KeVinDurant: 

[SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected abstract bool RunDialog(IntPtr hwndOwner);
下面可能是C++写的了。有没有调用Win32 API和SAT都是根据你的错误信息推测。想看真相,去找clr源码下载来看看
支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 10:51

@滴答的雨: clr源码??

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 10:56

@滴答的雨: 在哪里能看出调用了c++??

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 11:00

@KeVinDurant: 也可能是delphi。只是说已经不是C#了

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 11:04

@滴答的雨: 怎么看出不是C#???

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 11:05

@KeVinDurant:  reflector.exe能看到的就是C#开发的,当你发现这工具看不到的函数就是其他语言开发的

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-19 11:08

@滴答的雨: 但这样也不能说明SaveFileDialog不是用c#写的吧。。能举例其中哪个方法是调用了C++或者delphi的吗??

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 11:13

@滴答的雨: 看到了。调用了外部函数。。怎么跟调用win32 api不同的。。??没有看到引入命名空间什么之类的???

支持(0) 反对(0) KeVinDurant | 园豆:5 (初学一级) | 2013-03-19 11:22
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册