Q:子线程如何使用FolderBrowserDialog
A:
private
void
button1_Click(
object
sender,EventArgse)
...
{
System.Threading.Threads
=
new
System.Threading.Thread(
new
System.Threading.ThreadStart(test));
s.ApartmentState
=
System.Threading.ApartmentState.STA;
s.Start();
}
public
void
test()
...
{
System.Windows.Forms.FolderBrowserDialogdlg
=
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
IntPtrSHBrowseForFolder([In]UnsafeNativeMethods.BROWSEINFOlpbi);
[DllImport(
"
shell32.dll
"
)]
public
static
extern
int
SHCreateShellItem(IntPtrpidlParent,IntPtrpsfParent,IntPtrpidl,
out
FileDialogNative.IShellItemppsi);
public
static
int
SHGetFolderPathEx(
ref
Guidrfid,
uint
dwFlags,IntPtrhToken,[MarshalAs(UnmanagedType.LPWStr)]StringBuilderpszPath,
uint
cchPath);
[DllImport(
"
shell32.dll
"
,EntryPoint
=
"
SHGetFolderPathEx
"
)]
private
static
extern
int
SHGetFolderPathExPrivate(
ref
Guidrfid,
uint
dwFlags,IntPtrhToken,[MarshalAs(UnmanagedType.LPWStr)]StringBuilderpszPath,
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(IntPtrpidl,IntPtrpszPath);
[DllImport(
"
shell32.dll
"
)]
public
static
extern
int
SHGetSpecialFolderLocation(IntPtrhwnd,
int
csidl,
ref
IntPtrppidl);
[DllImport(
"
shell32.dll
"
)]
public
static
extern
int
SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)]
string
pszPath,
out
IntPtrppIdl,
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,EventArgse)
...
{
System.Threading.Threads
=
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.FolderBrowserDialogdlg
=
new
FolderBrowserDialog();
dlg.ShowDialog();
}
其实使得这个调用成功的原因不是在于Invoke,还是线程模式。如果把main函数上边的[STAThread] 去掉的话,文章开始处的错误仍然会发生。Invoke只是让主线程来执行子线程的调用函数。[STAThread]在程序入口处即将主线程置为sta模式,如果没有这句话将置为mta模式。而且线程模型一旦确定将不可以更改,所以你无法在其他地方用代码来设置主线程的线程模型。
分享到:
相关推荐
子线程更新主线程数据(再谈多线程)
主要介绍了C#子线程更新UI控件的方法,在桌面应用程序中控制UI界面有着不错的实用价值,需要的朋友可以参考下
java 子线程通过观察者模式通知主线程
c#子线程如何读取及设置主线程ui的值,自己录的一个小视频,方便理解,比较菜鸟的方法,请勿喷!
Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码...
C#子线程刷新主线程示例源码 功能介绍: 使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 技术特点: 使用了多线程实现了子线程刷新主线程 ,使用委托刷新主线程。 注意: 开发环境为...
子线程任务发生异常,主线程事务如何回滚
Android ,非MainActivity类中的子线程和UI线程通讯,并且获取子线程传递的信息,更新UI界面。需要使用okHttp类库
本资源详细介绍了主线程和子线程之间的通信过程,通过实例讲解了参数如何传递
Unity除了一些基本的数据类型,几乎所有的API都不能在子线程中调用,如果项目中有一段很耗时操作,unity可能会出现“卡死...因此针对这个问题再加上查找了一些资料,弄出了一个小工具,可以子线程与主线程的相互访问。
C# Winfrom必须掌握的技术,主线程显示数据,子线程获取数据,这是我做项目实际用到的技术。
Handler消息传递详解,子线程到子线程,主线程到子线程,子线程到主线程 三种消息,Looper,Handler工作机制详解 https://blog.csdn.net/shoneworn/article/details/80447651
Android中两个子线程的通信demo
子线程创建界面组件
1。 子线程操作主线程的示例 2。 全部源代码
Qt的子线程无法直接更新主UI,需要发送信号到主线程进行更新,我用的QTableWidget展示数据。
Ios子线程渲染Opengl 的demo, 减少在主线程操作,减少对其他View的影响造成的卡顿。
Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程...
通过窗口传递让主线程触发FIRE事件(子线程不能触发)
多个子线程运行,当所有子线程运行完毕,监控线程退出,并且返回所有子线程取得的数据。