.Net framework 4 來了

很難得會寫這個,這是今天剛好看到的What’s New in the .NET Framework 4,所以就順便記了一下,這次微軟也加了不少東西到 .Net 4 裡。
下面就簡單的條列,詳細的內容還是要看原文章比較清楚。
以前用 1.1/2.0/3.0/3.5 編譯的程式,現在 .Net 4.0 不接受了,除非你有在 configuration file 裡指定 supportedRuntime 或者用 .net 4 重新編譯才行。
In-process side-by-side,可以在同一個 process 載入多個版本的 .Net CLR,這還蠻神奇的。
Diagnostics、效能、GC、DLR 跟 generic 的加強
Embed Interop,這個看起來是可以把原本 Interop assembly 的 type 資訊嵌到你專案裡,這樣 deploy 的時候就不需要拿那個 Interop Assembly 一起 deploy>
新的型別:BigInteger、Complex 跟 Tuple
File System 直接提供 enumerator ,不用自己刻了。
支援 Memory-mapped file 跟 64 bit
類別庫裡也多了不少更方便的類別或者是為原有的 method 提供了更方便的 overload…還有 MEF、Parallel Computing、Networking、Web(ASP.Net)、WCF、WWF、ADO.Net …等等。
ASP.Net 的部份可以看這裡:ASP.NET 4 and Visual Studio 2010 Web Development Overview

Clipboard hooking in Gtk#

Windows 下要攔截 Clipboard 的事件處理的話,除了要 override WndProc 以外,還得利用 Windows 提供的函數 SetClipboardViewer()、ChangeClipboardChain()、SendMessage() 來告訴 Windows 說,你的程式會處理 Clipboard。

那在 Gtk# 下要怎麼作呢?

答案是處理 Clipboard 的 OwnerChange 即可,所以程式可以這樣寫:

	private Gtk.Clipboard m_clipboard;
public MainWindow (): base (Gtk.WindowType.Toplevel)
{
// Other stuff...
m_clipboard = Gtk.Clipboard.Get( Gdk.Selection.Clipboard );
m_clipboard.OwnerChange += new OwnerChangeHandler( delegate( object o, OwnerChangeArgs args ) {
m_clipboard.RequestText( delegate(Gtk.Clipboard clipboard, string text) {
Console.WriteLine( "text={0}", text );
} );
} );
}

首先要取得系統的 Clipboard,所以用 Clipboard 的 static function:Get 來取得,接著再指派我們的處理事件進去就行了。相對於 Windows 上的來說,簡單很多。

我有參考 glippper (gnome提供的剪貼簿工具,用 python 寫的),他拿了不只一個剪貼簿,它還用 GetForDisplay 去拿了另一個剪貼簿,我不知道有什麼差別,或許是處理多螢幕或是從遠端連進來時的情況吧~就目前來說,我應該暫時不必要照著glipper這樣作。

Gtk 裡的 trayicon:StatusIcon

Windows 的 Tray Icon 基本上就是對應到 Gtk 的 StatusIcon,用法蠻簡單的,在繼承自Gtk.Window的類別裡增加一個成員:Gtk.StatusIcon m_icon,然後在 constructor 裡加入:

		m_icon = new Gtk.StatusIcon();
m_icon.File = "./your_icon.png";
m_icon.PopupMenu += new PopupMenuHandler( delegate( object o, PopupMenuArgs args ) {
Console.WriteLine( "click" );
} );

這樣就可以動了。

當在 Icon 按下右鍵時,就會觸發 PopupMenu 事件。

mono 與 ssl

昨天在試 dotplurk 時,遇到了這個錯誤: unhandled Exception: System.Net.WebException: Error getting response stream (Trust failure): TrustFailure 。
循線追查,根據這篇:UsingTrustedRootsRespectfully,首先認為可能是 dotplurk 沒有做遇到未知憑證的處理。但是後來想想不對,因為 Browser 並沒有報遇到未知憑證的錯誤。
再繼續找,才又在這篇FAQ: Security,找到正解!因為 Mono 預設是不信任所有憑證的!!

That's probably because you do not trust the site you are connecting to. Note that a default installation of Mono doesn't trust anyone! 

那麼該怎麼解決呢?我後來是根據FAQ: Security所提供的第3種方法:以 mozroots.exe 去安裝 Mozilla 所有的根憑證就解決了。
微軟的 .Net famework 預設似乎是使用 IE 的,所以除非遇到未知的憑證,否則是不會遇到這種問題的。

在編譯時期判定是mono或microsoft.net

Mono 提供的 FAQ: Technical有提到如何動態判定版本與環境,但我找了好多文件都沒有提到在編譯時期是否有預設的 symbol 可用來判定。
看來只能在用 gmcs 編譯時加入 /d:MONO 了,這樣我就能在程式裡用 #if MONO 或 #if !MONO 來判定了。

Port Mini c# Lab to mono

在 Linux mono 平台上缺少了一個輕量級的開發工具,而 snippetcompiler 又沒有 open source,所以腦筋就動到 黑暗執行緒 開發的 Mini C# Lab 上。

下載原始碼以後,先試著用 MonoDevelop 開啟,但卻因為路徑與檔名問題失敗,Linux 使用的路徑分隔字元與 Windows 不同,對大小寫檔名也比較嚴格,調整以後,就能開啟了。

接著去編譯,稍微調整 References 以後,也可以順利編譯。

最後要執行了,卻出現下面的錯誤:

Unhandled Exception: System.EntryPointNotFoundException: HideCaret
at (wrapper managed-to-native) ICSharpCode.TextEditor.Caret:HideCaret (intptr)
at ICSharpCode.TextEditor.Caret.DisposeCaret () [0x00000]
at ICSharpCode.TextEditor.Caret.RecreateCaret () [0x00000]
at ICSharpCode.TextEditor.TextArea.OptionsChanged () [0x00000]
at ICSharpCode.TextEditor.TextArea..ctor (ICSharpCode.TextEditor.TextEditorControl motherTextEditorControl, ICSharpCode.TextEditor.TextAreaControl motherTextAreaControl) [0x00000]
at (wrapper remoting-invoke-with-check) ICSharpCode.TextEditor.TextArea:.ctor (ICSharpCode.TextEditor.TextEditorControl,ICSharpCode.TextEditor.TextAreaControl)
at ICSharpCode.TextEditor.TextAreaControl..ctor (ICSharpCode.TextEditor.TextEditorControl motherTextEditorControl) [0x00000]
at (wrapper remoting-invoke-with-check) ICSharpCode.TextEditor.TextAreaControl:.ctor (ICSharpCode.TextEditor.TextEditorControl)
at ICSharpCode.TextEditor.TextEditorControl..ctor () [0x00000]
at (wrapper remoting-invoke-with-check) ICSharpCode.TextEditor.TextEditorControl:.ctor ()
at MiniCSharpLab.Form1.InitializeComponent () [0x00000]
at MiniCSharpLab.Form1..ctor () [0x00000]
at (wrapper remoting-invoke-with-check) MiniCSharpLab.Form1:.ctor ()
at MiniCSharpLab.Program.Main (System.String[] args) [0x00000]

問題應該就出在 ICSharpCode.TextEditor.dll 裡,有空再用 MoMA 來分析或挖 ICSharpCode.TextEditor.dll 看看好了。

FileSystemWalker

用 foreach 以遞迴方式去找出所有檔案根目錄,順便練習 yield。

class FileSystemWalker
{
private string _path = "";
public FileSystemWalker(string path)
{
_path = path;
}
public IEnumerable<FileSystemInfo> Walk()
{
foreach( string d in Directory.GetDirectories( _path ) )
{
DirectoryInfo di = new DirectoryInfo( d );
yield return di;
FileSystemWalker walker = new FileSystemWalker(Path.Combine(_path, d));
foreach (FileSystemInfo fsi in walker.Walk())
yield return fsi;
}
foreach (string f in Directory.GetFiles( _path ) )
{
FileInfo fi = new FileInfo(f);
yield return fi;
}
}
}
class Program
{
static void Main(string[] args)
{
foreach(FileSystemInfo fsi in new FileSystemWalker(@"f:").Walk())
{
if( fsi.Attributes == FileAttributes.Directory )
Console.WriteLine( "[D]{0}", fsi.FullName );
else
Console.WriteLine("[F]{0}", fsi.FullName);
}
Console.ReadLine();
}
}

c# 的 static ctor()

沒看 c# in depth,還真不知道可以在 ctor 前加上 static 的修飾詞。以下是實驗結果:

using System;
namespace Sample
{
class Class1 {
static Class1() {
// Name="static"; // 不行,static function 只能存取 static member
StaticName = "StaticName";
Console.WriteLine( "Class1 static ctor()" );
}
public Class1() {
Console.WriteLine( "Class1 ctor()" );
}
public Class1( string name ) {
Console.WriteLine( "Class1 ctor( string )" );
Name = name;
}
public string Name { private set; get; }
public static string StaticName;
}
class MainClass
{
public static void Main(string[] args)
{
Class1 obj1 = new Class1("obj1");
Class1 obj2 = new Class1();
Class1 obj3 = new Class1("obj3");
Console.WriteLine("Hello World! {0}", Class1.StaticName );
}
}
}

執行結果如下:

Class1 static ctor()
Class1 ctor( string )
Class1 ctor()
Class1 ctor( string )
Hello World! StaticName

可以很清楚看到,無論如何,static ctor() 都會先被執行到,而且只會被執行一次。這很適合用來初始 static member。

monodevelop 2.0 + asp.net mvc

翻譯 monodevelop 2.0 的時候,有看到跟 MVC 相關的字串,可是跑 monodevelop 2.0 的時候,卻從沒看過。參考了這篇:ASP.NET MVC MonoDevelop Addin Preview,才知道要另外裝上,於是打開 Addin Manager 把 MVC Addin 裝上,試著寫一個簡單的 Hello world,真的是可以開發,看來可以不必被綁在 Visual Web Developer express 上了。
這篇ASP.NET MVC Preview: Using The MVC UI Helpers是額外挖到的,相當有用,對 Html helper 做了詳細介紹,作者就是 ASP.Net MVC 的開發者之一。

Upgrade Mono to 2.4.2.3 in Ubuntu Jaunty

網路上能看到的,多半都是自己編譯 tarball…

  1. 下載 mono in karmic 頁面 File 指示的三個檔案,先解開 mono_2.4.2.3+dfsg.orig.tar.gz,然後切到解開後的目錄下,打上 patch: cat mono_2.4.2.3+dfsg-1.diff.gz | gunzip | patch -p1,再用 chmod +x 幫 debian/rules 加上可執行的屬性。
  2. 安裝必要的套件: sudo apt-get install debhelper dpkg-dev libglib2.0-dev bison libtool dpatch libxml-dom-perl libxslt1-dev dc, lsb-release, libx11-dev libxt-dev zlib1g-dev autoconf automake
  3. 打開 debian/shlibs.local,把 libsqlite3 後面的 3.6.13 改為 3.6.10,因為 9.04 的 sqlite 是 3.6.10 版。
  4. 切到 mono 下,開始 build: cd mono;dpkg-buildpackage
  5. 把打包好的 deb 作成 local repository: 假設你把這些 deb 都放到 /opt/mono_debs 下,然後建立 Packages.gz: cd /opt/mono_debs && dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz。
  6. 新增 apt repository:在 /etc/apt/sources.list.d/ 下新增一個 mono.list,裡面放:
    deb file:///opt/mono_debs ./

    接下來就可以用 apt-get update、apt-get upgrade 來更新了。

理論上,這樣就可以更新了,但是事實上,因為 dependency 的關係,apt 會試圖安裝舊的 2.0.1 的 deb 來滿足相依性而導致應用程式有問題。
最好,也循上述的方法,把相關的基底 gtk-sharp2、xsp、gecko-sharp、mono-addins…等套件也重新 build 一次,這樣出現問題的情況應該會減少許多。
我個人建議,要用最新的 mono 還是衝 Karmic (9.10) 吧,這樣會省事很多。