http://blog.sina.com.cn/s/blog_4493d3b50100u6vi.html
[STAThread]--Single-Thread Apartment
在C#中用在Main()函數之前,指定當前線程的ApartmentState是STA,用在其他方法上沒有作用。
有時根據設計需要,需要同COM進程進行交互,例如使用Windows clipboard。
以下引用另一同輩的發言:http://blog.csdn.net/qilang/archive/2006/06/06/775605.aspx
STA不是單線程的意思.英文爲single threaded apartment.是一種套間(或譯爲公寓)線程模式.
sta thread並不表明應用程式的類型,和應用程序不搭界,恰相反,一個應用程序可以有多個線程.每個線程也可以有多個組件或對象.以前win16位系統的組件線程模式才真正是單線程.這是一種被淘汰了的模式.
線程模式用於處理組件在多線程的環境裏並行與並互的方式.比如套間線程(STAThread)模式中接口跨線程傳遞必須被調度(Marshal),不調度直傳肯定會失敗!而MTA或FreeThread模式中的接口可以不經調度直接傳遞.
這種調度在特定的環境中非常影響性能(可有幾百倍之差).如VB裏只支持STAThread模式.FreeThread模式的組件會在裏面表現成和跨進程一樣慢!
線程模式是微軟的COM基礎中的極其重要的概念.一定要吃透!
我對.net真是一竅不通(沒空去弄,對不起微軟去年的獎賞).但我可以肯定,C#中的[STAThread]屬性是應用程序的套間初始化代碼.可以直接理解成SDK裏的
CoInitialize(NULL);
初始一個STA套間實際上是相當於開了一個消息窗口,所有調用經此窗口過程調度到組件內.
同理[MTAThread](不知有沒有這個屬性,自已去查)
可以理解成
CoInitializeEx(NULL,COINIT_MULTITHREADED )
這經常是一個對初入com大門的人來說,有一定難度但必須過的一道關.
=====================================================================================
C#學習筆記(一)-- 入門的困惑
簡單的我就不寫了,主要寫一下C#學習中的要點和難點。
1.由HelloWorld開始
先看一段基本上每本C#書裏都會講到的例子,很老土。
using System;
namespace test
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
System.Console.WriteLine("Hello,World!");
}
}
}
先引用一個命名空間System,再定義一個自己的命名空間test,裏面有一個類Class1,屬性[STAThread],一個入口的Main方法,注意:跟JAVA不一樣,Main首名母是大寫,Main必須是static的。不然怎麼開始呢?難倒要實例化才行?哈哈,定義爲static就是把它放在椎裏。這裏規舉。
2.命名空間
再來看看System.Console.WriteLine("Hello,World!");輸一名語名到控制檯。調用System命名空間裏的Console類的WriteLine方法。System命名空間是前面我們已經引用了的using System;
你也可以在引用的時候改個名字output,那麼在調用的時候就是output.Console.WriteLine("Hello,World!");
試一試:
using output=System;
namespace test
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
output.Console.WriteLine("Hello,World!");
}
}
}
運行報錯:F:\mydoc\Visual Studio Projects\test\Class1.cs(7): 找不到類型或命名空間名稱“STAThread”(是否缺少 using 指令或程序集引用?)
嘿嘿,是[STAThread]惹的禍。幹掉它。再試,搞定。
[STAThread]是Single Thread Apartment單線程套間的意思。是一種線程模型。其它的好像還是MTA(多線程套間)、Free Thread(自由線程)。這個屬性要加在主 Main 上。這個屬性只在 Com Interop 所用,如果全部是 managed code 則無用。簡單的說法:[STAThread]指示應用程序的默認線程模型是單線程單元 (STA)。啓動線程模型可設置爲單線程單元或多線程單元。如果未對其進行設置,則該線程不被初始化。
也就是說如果你用的.NET Framework,並且沒有使用COM Interop,一般不需要這個Attribute。
明白了吧。
注意,using指令是用於命名空間的。變化着用一下,也可以爲類創建別名:
using output=System.Console;
namespace test
{
class Class1
{
//[STAThread]
static void Main(string[] args)
{
output.WriteLine("Hello,World!");
}
}
}
這樣也行。。。
命令空間是可以嵌套的。如:
using System;
namespace test
{
namespace t1
{
class Class1
{
static void Main(string[] args)
{
System.Console.WriteLine("t1.Class1");
}
}
}
namespace t2
{
class Class2
{
static void Main(string[] args)
{
System.Console.WriteLine("t2.Class2");
}
}
}
}
運行,報錯。我是故意的(臺下:大騙子)。J不要扔磚頭啊。不要這麼容易就放棄嘛,要執着。
看錯誤F:\mydoc\Visual Studio Projects\test\Class1.cs(9): 程序“F:\mydoc\Visual Studio Projects\test\obj\Debug\test.exe”定義了不止一個入口點:“test.t1.Class1.Main(string[])”
因爲你的命名空間test裏定義了二個Main方法,所以呢,不用我說了吧。
using System;
namespace test
{
namespace t1
{
class Class1
{
static void Main(string[] args)
{
System.Console.WriteLine("t1.Class1");
System.Console.WriteLine(t2.Class2.MyFunction());
}
}
}
namespace t2
{
class Class2
{
public static string MyFunction()
{
return "t2.Class2";
}
}
}
}
外部程序引用的時候就是這樣:using test.t1;或using test.t2;
入門就這些問題。
打開Visual Studio .NET 2003 命令提示鍵入ILDASM,這個程序可以查看編譯後的元數據。
網上查一下Reflector這個軟件。幹什麼用的。反編譯呀。。。。寒。
=========================================================================
單線程套間(STAThread) vs. 多線程套間(MTAThread )
[原文鏈接]: STA Thread vs. MTAThread(WHost)
最近我遇到一個有趣的線程問題,想跟大家分享一下,以免大家也遇到這種容易混淆的問題。
打開一個其他人寫的C#程序,爲了下面的講解,我把這個程序叫作”DeltaEngine”。DeltaEngine會調用一個本地的程序集,並處理其中某些事件。然後建一個工程,把DeltaEngine作爲庫項目引用,這個工程又被一個VB程序引用。我把這個VB程序叫做"VBApp"。所以,引用結構就像:
VBApp (VB) -> DeltaEngine (C#) -> NativeCode
當我把VBApp作爲啓動程序運行時,它會一直等待NativeCode裏面的事件在DeltaEngine中被處理。我注意到,如果我把DeltaEngine作爲啓動程序來運行的話,事件就會像預期那樣得到處理。我花了很多時間想解決這個問題,但還是很困惑。
最後有人指出,VB項目的默認線程模型是單線程套間(SingleThreaded Apartment),而C#項目的默認線程模型是多線程套間 (Multithreaded Apartment)。因爲DeltaEngine最初是作爲C#工程開發的,被默認爲使用MTA。當使用VBApp作爲啓動程序調用DeltaEngine時,DeltaEngine就會使用STA。因爲這樣,DeltaEngine就會開始等待其實它已經喚起的事件,所以DeltaEngine會一直等待下去。如果我把DeltaEngine作爲啓動程序運行,它就會使用MTA並且會像預期那樣工作。
解決的方法就是把MTAThreadAttribute加進VBApp的主函數裏面。如下:
<MTAThread> Sub Main()
類似,如果你想把STAThread attribute加進C#的主方法裏面,如下:
[STAThread]
static void Main()
WindowsForms程序要求使用STA,所以創建C# Winapp後,你可以在Program.cs看見像這樣的代碼。
我就不重複一些已經有的關於STATread 和MTAThread的文件,所以我給出下面的一些link可以學到更多關於STATread 和MTAThread的東西。
STAThreadAttribute
http://msdn2.microsoft.com/en-us/library/system.stathreadattribute(VS.71).aspx http://blogs.msdn.com/jfoscoding/archive/2005/04/07/406341.aspx
MTAThreadAttribute
http://msdn2.microsoft.com/en-us/library/system.mtathreadattribute(VS.71).aspx
======================================================================================
C# 中WindowsForm 的初始化信息 [STAThread]
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
以上的代碼是VS 2005中默認的初始化信息.
Application.EnableVisualStyles();
簡單的說就是讓你的控件顯示出來.當然是在WindowsForm 中
此方法爲應用程序啓用可視樣式。如果控件和操作系統支持視覺樣式,則控件將以視覺樣式進行繪製。若要使 EnableVisualStyles 生效,必須在應用程序中創建任何控件之前調用它;EnableVisualStyles 通常是 Main 函數的第一行.
下面的代碼示例演示如何在 Main 函數中調用 EnableVisualStyles 來啓用應用程序的視覺樣式
對於支持FlatStyle屬性的控件,請確保將FlatStyle屬性設置爲FlatStyle.System值。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace VStyles
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
this.button1 = new System.Windows.Forms.Button();
this.button1.Location = new System.Drawing.Point(24, 16);
this.button1.Size = new System.Drawing.Size(120, 100);
this.button1.FlatStyle = FlatStyle.System;
this.button1.Text = "I am themed.";
// Sets up how the form should be displayed and adds the controls to the form.
this.ClientSize = new System.Drawing.Size(300, 286);
this.Controls.Add(this.button1);
this.Text = "Application.EnableVisualStyles Example";
}
}
}