zoukankan      html  css  js  c++  java
  • 子线程使用FolderBrowserDialog的问题延伸

    Q:子线程如何使用FolderBrowserDialog  

    A:

    private   void  button1_Click( object  sender, EventArgs e)
            
    {
                System.Threading.Thread s 
    =   new  System.Threading.Thread( new  System.Threading.ThreadStart(test));
                s.ApartmentState 
    =  System.Threading.ApartmentState.STA;
                s.Start();
            }


            
    public   void  test()
            
    {
                System.Windows.Forms.FolderBrowserDialog dlg 
    =   new  FolderBrowserDialog();
                dlg.ShowDialog();
            }

    以上代码简单的演示了FolderBrowserDialog在子线程中的使用,其中设置线程的ApartmentState为System.Threading.ApartmentState.STA是关键的语句。在.net2.0中应该使用

    s.SetApartmentState(System.Threading.ApartmentState.STA);

     如果没有上述设置会报如下错误

    在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。

    如果你了解com的线程模型的话,应该已经清楚上面的问题根本了。
    我们先看一下 FolderBrowserDialog的实现方法,这个控件实现是通过ole的.可以用Reflector.exe看一下他的代码,调用了几个windows shell32的api。

    [SuppressUnmanagedCodeSecurity]
    internal   class  Shell32
    {
        
    //  Methods
         public  Shell32();
        [DllImport(
    " shell32.dll " , CharSet = CharSet.Auto)]
        
    public   static   extern  IntPtr SHBrowseForFolder([In] UnsafeNativeMethods.BROWSEINFO lpbi);
        [DllImport(
    " shell32.dll " )]
        
    public   static   extern   int  SHCreateShellItem(IntPtr pidlParent, IntPtr psfParent, IntPtr pidl,  out  FileDialogNative.IShellItem ppsi);
        
    public   static   int  SHGetFolderPathEx( ref  Guid rfid,  uint  dwFlags, IntPtr hToken, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath,  uint  cchPath);
        [DllImport(
    " shell32.dll " , EntryPoint = " SHGetFolderPathEx " )]
        
    private   static   extern   int  SHGetFolderPathExPrivate( ref  Guid rfid,  uint  dwFlags, IntPtr hToken, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath,  uint  cchPath);
        [DllImport(
    " shell32.dll " )]
        
    public   static   extern   int  SHGetMalloc([Out, MarshalAs(UnmanagedType.LPArray)] UnsafeNativeMethods.IMalloc[] ppMalloc);
        [DllImport(
    " shell32.dll " , CharSet = CharSet.Auto)]
        
    public   static   extern   bool  SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);
        [DllImport(
    " shell32.dll " )]
        
    public   static   extern   int  SHGetSpecialFolderLocation(IntPtr hwnd,  int  csidl,  ref  IntPtr ppidl);
        [DllImport(
    " shell32.dll " )]
        
    public   static   extern   int  SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)]  string  pszPath,  out  IntPtr ppIdl,  ref   uint  rgflnOut);
    }

    COM提供的线程模型共有三种:Single-Threaded Apartment(STA 单线程套间)、Multithreaded Apartment(MTA 多线程套间)和Neutral Apartment/Thread Neutral Apartment/Neutral Threaded Apartment(NA/TNA/NTA 中立线程套间,由COM+提供)。

    STA 一个对象只能由一个线程访问,相当于windows的消息循环,实现方式也是通过消息循环的,ActiveX控件、OLE文档服务器等有界面的,都使用STA的套间。 MTA 一个对象可以被多个线程访问,即这个对象的代码在自己的方法中实现了线程保护,保证可以正确改变自己的状态。

    所以创建和访问一个activex或者ole对象时,必须设置线程模式为sta。

    稍微有些多线程使用经验的人会发现用Control.Invoke方法也可以成功调用ole对象,比如上面的例子改为

    private   void  Form1_Load( object  sender, EventArgs e)
            
    {
                System.Threading.Thread s 
    =   new  System.Threading.Thread( new  System.Threading.ThreadStart(test));
                
    // s.SetApartmentState(System.Threading.ApartmentState.STA);
                s.Start();
            }


            
    public   delegate   void  dtest();

            
    public   void  test()
            
    {
                
    this .Invoke( new  dtest(invokeTest));
            }


            
    public   void  invokeTest()
            
    {
                System.Windows.Forms.FolderBrowserDialog dlg 
    =   new  FolderBrowserDialog();
                dlg.ShowDialog();
            }

                 其实使得这个调用成功的原因不是在于Invoke,还是线程模式。如果把main函数上边的[STAThread] 去掉的话,文章开始处的错误仍然会发生。Invoke只是让主线程来执行子线程的调用函数。[STAThread]在程序入口处即将主线程置为sta模式,如果没有这句话将置为mta模式。而且线程模型一旦确定将不可以更改,所以你无法在其他地方用代码来设置主线程的线程模型。

  • 相关阅读:
    DAY 42 前端
    DAY 41 mysql
    DAY 40 前端学习
    DAY 39 前端学习
    DAY 38 前端学习
    DAY 37 前端学习
    上传一个桌面
    找到anaconda中自带的qtdesigner,设计ui文件并生成py文件
    python课程:python3的数字与字符串
    python3 偏最小二乘法实现
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6204987.html
Copyright © 2011-2022 走看看