2012年1月31日

100篇達成!

就像玩遊戲一樣,有獎盃,有成就;老實說,完全沒想到已經達到100篇了,就在突然間,就發現已經突破100篇了;老實說,寫文章是一件苦差事,當解決問題後,想要把這個問題記錄下來,老實說,還要把問題重現,真的不是一件簡單的事情,如果邊解決問題邊記,我想也太耗時間了;讀書筆記其實也是同樣道理,但雖然是一件苦差事,但未嘗不是一件好事情!?健忘的我,用我自己懂的語言做筆記,那怕未來忘記,還可以輕易地去喚醒當時的記憶,而且常常有朋友問一些問題,如果Blog有寫過,就可以很開心的衝流量告訴對方位置,並且利用這個位置做解釋,其次,當要完成一篇文章,寫的過程中,會不斷的、反覆的推論任何的疑點,然後去查更多更多的資料,也讓自己更沒時間打電動務實,總之,累歸累,好處其實還是大於所花費的時間。

而今天超過100篇,也代表著一個新的里程,雖然每個月的文章數持續下降XDD,但一路走來,也代表著沒有放棄,而看著使用者人數持續成長 ( 雖然可能多半都是我自己= = ),也繼續勉勵我自己,能繼續走下去,把這些東西記錄下來。

而最後,這是一個小小的期許,也期望今年文章,能突破兩百篇,持續走向新的里程碑!

2012年1月21日

TFS - 路徑已在工作區XXX中對應之解決方案

最近因為原本的TFS主機掛點,再加上要和同事協同開發專案,於是就想利用Team Foundation Service ( 雲端版的TFS )來處理看看,結果在讓Team Foundation Service的版本控制,對應本地程式碼的時候,發生了下面這個錯誤。

路徑 C:\XXXX 已經在工作區 XXXXX 中對應

image

簡單說,就是因為這個目錄之前已經對應到那台掛掉的TFS,所以造成無法對應的狀況,而這時候,因為那台已經掛掉的TFS也無法連上去了,所以也沒辦法用比較方便的程序去做移除等處理,所以這時候,就必須使用tf.exe這個命令了。

tf.exe

這個管理工具是命令模式下的指令程式,他的路徑在C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe,所以我們必須使用視窗工具,並切換到這個目錄下。

image

當然這個工具其實還有許多的功能,但今天我們主要來利用此工具刪除工作區。

我們可以執行tf workspaces指令來查看目前這台電腦上有多少個工作區。

image

然後我們就可以使用tf workspaces /remove:工作區 /server:https://集合網址 的格式來移除。

假設工作區是SkyWorkspace、集合網址是http://tfs:8080/tfs/sky、那就可以使用

tf workspaces /remove:SkyWorkspace /server:https://http://tfs:8080/tfs/sky

來移除workspace,移除完畢後,這個目錄就可以對應到別台的TFS版控了。

2012年1月20日

Visual Studio中文版安裝英文版Silverlight

其實這個網路上已經有非常多的前輩有寫步驟了,但一查下來,幾乎都是簡體的,然後小弟有時候又容易忘記中文的碼,所以想一下,就乾脆用10分鐘順便紀錄一下這個過程。

如果我們使用Visual Studio中文版,要安裝Silverlight英文版,是會有問題的,簡單的說就是綁訂了語言。

Visual Studio 2010 SP1 That matches the language version of Silverlight 5 Tools must be installed before installation of Silverlight Tools can continue. Silverlight Tools is available in other languages at http://gomicrosoft.com/fwlink/?LinkId=177432

image

不過礙於小弟又是那種喜歡嘗鮮,但是英文超級苦手,不想裝英文版的Visual Studio,所以就採用修改檔案的方式。

修改檔案的方式不確定會不會造成怎樣的Bug,請自行斟酌。

方法很簡單,使用WinRAR工具,解開下載下來的EXE檔案,並放到某個目錄下面,修改ParameterInfo.xml這個檔案,可以用記事本或是其他編輯工具開啟。

然後Parameteinfo.xml所有的1033改成1028,改完後存檔。

接下來執行SPInstaller.exe進行安裝,就完成了。

另外,以下也有些超級神人Lolota前輩提供的方法,給大家參考。

http://www.dotblogs.com.tw/lolota/archive/2010/06/03/15599.aspx

2012年1月14日

TFS - 更換(移除)branch的圖示

老實說,這個問題很簡單,但是困擾我超久!,結果今天同事,輕鬆的解決,並告訴我這個解決法,看完之後,真的是簡單到無言…!!

這個的問題是,當我們在TFS製作Branch(分支)後,有可能merge(合併)回來,或是不小心做錯Branch,或是不需要Branch了,這時候,我們可能刪除了支線的檔案,但是主要的圖示,卻還是一職維持的分支圖案,甚至,還可以去查詢整個樹狀;如下圖,就算刪除了支線的檔案,但主要分出來的目錄結構,還是這個圖示。

image

而要怎樣改成一般的目錄結構呢!?其實很簡單,我們只要選擇上圖有Branch的圖示,然後點選最上方的檔案,原始檔控制,分支與合併,轉換成資料夾,這樣就可以了!!

image

老實說,我也搞不懂為何不在檔案右鍵上的選單做出這個功能,完全沒有想到,會放在這邊,這個問題困惑了很久,結果我同事,輕輕鬆鬆解決= =…,總之,紀錄一下,預防下次又完全找不到…

TFS - 完全移除版控的檔案

這裡提到完全移除,大家可能會很疑惑,甚麼叫做完全移除,其實我們在Visual Studio裡面刪除的檔案,還是存在SQL Server裡面的!( TFS版控會把檔案放到SQL Server裡面 ),所以還是有可能還原回來( 怎樣還原小弟我倒是沒試過 ),也會比較浪費空間;其次,如果分支出來的檔案,已經用不到了,我們也可以使用這個方法來真正的移除(刪除)。

image

那這部分怎麼做呢?,我相信大家在Visual Studio上面一定都找不到這個選項,因為他必須透過命令列模式的管理工具,他的路徑在C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe,所以我們必須使用視窗工具,並切換到這個目錄下,其實這個工具有非常多的功能,而今天我們稍微介紹其中一個功能。

image

接下來,我們透過

tf destroy /preview 專案位置 /collection:主機位置

指令來看看要刪除的檔案,因為加上/preview,所以只會預覽,並不會真的刪除掉。

image

如果確定無誤後,就可以把/previews拿掉,然後真實的刪除掉;他這邊會再做一次確認,如確認無誤,按下"Y",就會開始執行。

image

然後就會順利執行完畢=W=,如果只是要單獨刪除一個檔案也是可以的,參考資料裡面有附上官方的說明,有興趣的可以去看看。

參考資料

2012年1月12日

Hyper-V - RemoteFX 讓你遠端登入並且執行3D遊戲!

2012/05/02 小更新 -  更新RemoteFX 3D無法啟動之問題。

這幾天剛好在弄Hyper-V的一些東西,想到Windows Server 2008 R2 SP1搭配Win7 SP1,有支援遠端執行3D的功能,所以就實際的來試驗看看,中間有一些過程和心得,就在這邊順便記錄下來。

RemoteFX

RemoteFX,這個東西就不多講了,而且講了搞不好還講錯XD,所以有興趣的可以參考這個網址,簡單的說,就是利用這個技術,可以達到遠端桌面執行3D的功能;但這個功能只有Windows Server 2008 R2 SP1當作Hyper-V的主機,虛擬一個裝有Win7 SP1的VM,並且使用WIN7 SP1的遠端桌面功能,才能達成。

目的!?

至於為何要使用這個的目的,對我來說,重點當然遊戲啊!!畢竟身為宅男,遊戲才是一切,而目前的筆電,也因為某些原因,不能順利執行遊戲QQ..當然對於企業來說,遠端桌面執行3D,也是有許多功用,我相信這個大家應該都能想到=W=

結論

會把結論放在前面,是怕有人很開心的設定玩,結果不如預期,然後來公幹我= =…基本上小弟的Server是裝Nvida GT260,配上I7 CPU,但是跑起來的效果,並沒有想像中好,但這也有可能牽涉到I/O的部分,畢竟這台上面,我裝了很多東西XDD…但網路上也有許多神人可以玩重資源的遊戲,未來有機會,再繼續分享吧XDD。

開始吧!!

就如前面所說,我們必須要先有一台裝有Windows Server 2008 R2 SP1的主機,並且裝上Hyper-V的服務,其次,我們也要先準備好Win7 SP1的VM,完成後大概如下圖,我們可以看到我裝了一個名稱為Game Server的VM。

image

打開Game Server裡面看看,我們會發現新增硬體有一個RemoteFX 3D 視訊卡;沒錯,這就是今天的重點,但是我們現在貿然的新增,雖然不至於讓電腦爆炸,但電腦會告訴你錯誤,那是因為我們還沒有安裝遠端桌面服務。

image

我們打開伺服器管理員,並且新增角色。

image

然後勾選遠端桌面服務。

image

然後選擇遠端桌面虛擬主機的兩項角色服務"核心服務"和"RemoteFX",然後按下下一步後,就會開始安裝,並請會要求重新開機,所以這邊如果有許多VM在執行,要注意一下喔!

image

開完機後,我們就可以回到VM的管理介面,去把Game Server的RemoteFX 3D 視訊卡 新增進去。

image

新增進去後,就可以調整一下設定細節,並且重新將Game Server啟動起來。

image

如果我們是利用Hyper-V管理員來檢視VM的話,可能會看到這個畫面,"已中斷視訊遠端存取連線"的警告,這就代表已經成功一半了=W=,因為RemoteFX需要搭配RDP 7.1才能順利進行,而有支援RDP 7.1的,就只有Windows Server 2008 R2 SP1和Win7 SP1的遠端桌面連線;如果沒看到這個畫面,也可以繼續往下看。

image

2012/05/02更新 -  如果沒看到這個畫面,那表示顯示卡的驅動可能沒有改成RemoteFX 3D的顯示卡,我們只要Windows 7的裝置管理員下的視訊控制卡( VGA相容 )的地方,按下滑鼠右鍵,並且選擇更新驅動程式,之後再選擇讓系統自己尋找,就可以順利找到RemoteFX的顯示卡。

image

這時候,回到Client端,也就是準備要連結Win7這台VM的機器,我們就可以準備使用遠端桌面連線進行遠端的登入。

image

接下來,我們要進行一些小設定,按下選項,打開細部的設定選單。

image

在顯示這邊,色彩記得要是最高品質。

image

然後音訊的部分,也要做設定。

image

設定如下。

image

如下,全勾吧,並且將連線速度,設為最大!

image

然後就可以順利連進去了,如果中間有出現憑證問題,可以不用管他,到這邊,我們來看一下裝置管理員。

image

然後看一下DirectX的支援程度,我們執行dxdiag來看看支援程度,如果不知道如何看可以參考這裡

image

最後,我們再執行3DMark06來測試看看!

image

執行完的結果=w=。

image

補充資訊

在國外,也有一些設定不正確可能會導致RemoteFX功能失敗,下面就列出來給大家參考。

防火牆

其實我裝完後,通常VM上面的WIN7 SP1防火牆也自動幫我設定好了,這邊也提出來給大家參考看看。

image

啟用一些效能上設定

在VM的WIN7 SP1上,還有一些設定可以改變效能,我們執行gpedit.msc來改變管理範本。

image

然後目錄位置在,電腦設定 / 系統管理範本 / Windows元件 / 遠端桌面服務 / 遠端桌面工作階段主機 裡面,有兩個需要調整,一個是"設定RemoteFX”另外一個是"使用RemoteFX時最佳化視覺效果"。

image

其中"設定Remotefx"很簡單,只要啟用就可以了,另外最佳化的部分,就把他調到最高品質。

image

這樣就完成了設定。

KVM Switch

有些可以使用ip切換的KVM Switch,可能需要在Hyper-V上面裝RemoteFX Cap Driver,裝法很簡單,只要在終端機key上以下指令。

dism /online /enable-feature /featurename:Microsoft-Windows-RemoteFX-EmbeddedVideoCap-Setup-Package

然後按下Enter就好了;實際上我沒測試過,因為我也沒這方面的機器。

如果要解除安裝,就執行以下指令

dism /online /disable-feature /featurename:Microsoft-Windows-RemoteFX-EmbeddedVideoCap-Setup-Package

一樣按下Enter就可以了。

結論

老實說,這真的很好玩XD,但還是要注意的是,目前只有WIN7 SP1才有支援RDP 7.1,所以我用MAC的Microsoft Remote工具,是沒辦法執行3D效果的,還是必須在MAC上面VM一個WIN7 SP1,再利用WIN7 SP1遠端登入那台遙遠的VM;其次,目前我還沒真正的裝遊戲進去玩XDD,所以實際遊玩狀況,還不是很清楚;最後,如果有人願意借我一張效能超強的卡王XD,也非常歡迎喔!我也滿想看看,效能可以到怎樣的程度,總之,如果家裡有PC,又裝Hyper-V,可以考慮這樣玩玩看!

參考資料

2012年1月10日

C# - Equals和等於等於( 等於比較運算式 )

這個故事的起源,是在寫一個測試程式,其內容要比較兩個物件的相等,想當然爾,原生的Object.Equals和等於等於是不能使用的,而後,衍生出一堆的問題出來XDD,因為年紀大了,要預防老年癡呆,過了一兩天就忘記的狀況,所以趕快把它紀錄下來。

Ojbect.Equals

這個的起源,必須要從Object.Equals講起,我們先看一下Object.Equals反組譯後的內容。

public virtual bool Equals(object obj)
{
    return RuntimeHelpers.Equals(this, obj);
}

就是這樣,他只是簡單的呼叫RuntimeHelpers.Equals,而這個方法,其實只是去比較是否為相同的執行個體,簡單的說,如果new了兩個物件,就算內容相同,還是會傳回False,而我們自己撰寫的類別,預設當然也是繼承Object,所以自然而然,也也繼承了Equals這個方法。

Object.Equals靜態方法

接下來是Object.Equals的靜態方法,以下是反組譯後的程式碼,最核心的一段是objA.Equals(objB),簡單的說,他還是去調用了objA的Equals方法。

public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}

所以說Object.Equals靜態方法依舊是使用了自身的Equals。

等於等於 ( = = ) 比較運算子

關於等於的比較運算子,我先引用一下MSDN的一段話。

對於預先定義的實值型別 (Value Type),等號比較運算子 (==) 在運算元相等時傳回 true;否則傳回 false。 對於 string 以外的參考型別,若兩個運算元參考到同一物件,== 會傳回 true。 對於 string 型別,== 會比較字串的值。

這段話的意思是說,如果是int這種Value Type,值相等的時候,就會傳回True,否則會傳回Fase,而參考型別,則必須要指到同一個物件,否則會傳回False,除了string以外,所以簡單的說,int、String等等我們常用的型別,都可以正確的幫我們比較到值,但如果是物件與物件內容的比較,很抱歉,只要它們參照到的是不同位置,就算內容相同,還是會傳回False。

String.Equals(Object)

這個就是Override了Object.Equals的方法,並且判斷傳入進來的型別是否為String,比較重要的是後面那段,第一步它會判斷是否參考到同一個位置( 利用object.ReferenceEquals ),如果是同一個位置,當然不用講,就絕對相同了,但如果是不同位置,他還會利用底層的EqualsHelper方法來看看內容值是否相等。

public override bool Equals(object obj)
{
    if (this == null)
    {
        throw new NullReferenceException();
    }
    string strB = obj as string;
    if (strB == null)
    {
        return false;
    }
    return (object.ReferenceEquals(this, obj) || EqualsHelper(this, strB));
}

所以雖然String也繼承於Object,但他複寫了Equals,所以我們可以輕鬆地去比對兩個字串是否相等。

String.Equals(String)

另外一個string.Equals(String)反組譯後如下,基本上和上面的差不多,差別於,這個是直接傳入String並非Object型別。

public bool Equals(string value)
{
    if (this == null)
    {
        throw new NullReferenceException();
    }
    if (value == null)
    {
        return false;
    }
    return (object.ReferenceEquals(this, value) || EqualsHelper(this, value));
}

接下來是String的等於等於。

String的等於比較運算子

在String裡面寫了等於比較運算子,寫法如下,使用operator關鍵字來處理,所以我們這邊可以看到,其實String的等於比較運算子,實際上是呼叫String.Equals(String,String)這個靜態方法

public static bool operator ==(string a, string b)
{
    return Equals(a, b);
}

接下來我們看一下String的靜態方法。

String.Equals(String,String)

String也有Equals靜態方法,內容如下。

public static bool Equals(string a, string b)
{
    return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b)));
}

這裡比較奇怪的是a==b這段,原則上如果a和b都是字串了,則應該又會進入string靜態的Equals,但這邊感覺上只是去比對位置是否相等;畢竟程式碼是反組譯出來的,真實程式碼是否這樣子,也不能確定,但可以確定的是,String的等於比較運算式,實際上還是回到了Equals方法裡面,這點MSDN也有提到。

Int32.Equals(Object)

接下來,我們看看Int32的部分,這部分也是Override,沒有甚麼太特別之處。

public override bool Equals(object obj)
{
    return ((obj is int) && (this == ((int) obj)));
}

其次是Int32.Equals(Int32)的部分

Int32.Equals(Int32)

這部分就更簡單,Int32是實質型別,所以也沒有甚麼比對位置或是值的問題。

public bool Equals(int obj)
{
    return (this == obj);
}

同樣的Int32是實質型別,所以Int32也沒有復寫等於運算式。

初步的結論

所以,到此,我們這邊初步的結論,如果是要比較兩個物件的內容,無論是使用比較運算子(等於等於 == )或是使用Equals,通通都只會比較是否參考到同一個位置,所以只要參考的位置不同,兩個物件的內容就算相同,很不幸的,還是傳回False。

但如果是int或是strting,無論是使用比較運算子(等於等於 ==)或是使用Equals,都會比較值,只要值不同,就會傳回False。

複雜的問題

接下來就是幾個大家常見的複雜問題。

object a = 1;
object b = 1;
bool value = a == b;
bool value2 = a.Equals(b);

第一個最常見的應該就是這個了吧,答案第一個value是false,第二個value2是true,那是因為1 這個值已經被Boxing起來了存成object型別了,所以當使用等於比較運算式時,就等同於object == object,所以依照上面的理論,除了Int和string以外,除非位置相同,不然都會傳回false,而這邊又因為Boxing的關係,所以它們的位置是不同的。

關於第二個答案是True的關係,那是因為雖然被包成Object型別,但骨子裏面還是Int32,基於多型的概念,實際上,執行的這個Equals,是執行Int32.Equals(Object),所以對照上面,就會變成比較值是否相等。

基本上這個問題是一般大家網路上已經可以常常看到的問題了,接下來是這段。

object c = "a";
object d = "a";

bool valueString = c == d;
bool valueString2 = c.Equals(d);

答案是兩個都是True!,為什麼呢?這裡隱藏了一個陷阱,如果以剛剛的理論來說,等於比較運算式,非實質型別和String的時候,都會只會比較位置,但這裡的c == d的部分,兩個都是object,所以只會比較位置,理論上,會產生兩個string”a”,且不同位置,所以應該會是false阿,但這裡卻為True!,所以表示位置一樣!?,是的,沒錯,這裡的位置真的一樣,因為CLR存在著一種機制,當它初始化時,它會創建一個內部hash,其中key是我們所要存放的字串,而value是誰引用。當定義一個新的string 時,系統會檢查是否有相同的。如果找不到,就建立一個新的,如果找到就直接引用,所以這邊位置是相同的。

所以實際上要怎樣做,才會產生兩個字串呢!?我們直接new一個新的字串,這樣他就不會自動幫忙檢查了。

object e = new string('a', 1);
object f = new string('a', 1);

bool valueStrin3 = e == f;
bool valueString4 = e.Equals(f);

如果是這樣,比對出來的結果,第一個就是False,第二個是True。

結尾

其實等於比較運算式在實質型別裡面,是沒有甚麼問題的,因為實際存放的東西,就是實質,例如:1、a這類東西,所以等於比較運算式會去比較兩個記憶體上的實質,其實是沒甚麼問題的,但是如果是參考型別,雖然物件內容可能一樣,但實際上,存放在記憶體的實質,只是個位置,而這兩個物件的位置,一定不一樣,所以等於比較運算式,只會比對出兩個位置不同;在Java的String和C#一樣,都是物件,所以存放在記憶體上的都是位置,但有點不一樣的是,C#有幫忙復寫了等於比較運算式,他裡面實際上會去呼叫String的Equals,所以在C#上使用等於比較運算式,能比較出真正String的值,但Java裡面,就只能使用Equals了。

參考資料

2012年1月9日

ASP.NET MVC - Helper Namespace錯誤

最近開啟了一個很久沒開的專案,想說拿來試著升級到最新版的ASP.NET MVC,不看還好,一看,就整個吐血;整個的View都產生如下面畫面的錯誤。

image

錯誤訊息如下。

System.Web.WebPages.Html.HtmlHelper' 不包含 xxx 的定義,也找不到擴充方法 xxx 來接受型別 'System.Web.WebPages.Html.HtmlHelper' 的第一個引數 (您是否遺漏 using 指示詞或組件參考?)

簡單的說,就是Namespace錯誤的問題,原則上MVC的Html Helper的命名空間是System.Web.MVC.HtmlHelper底下,但是這邊卻是取尋找System.Web.WebPages.Html.HtmlHelper,所以產生了這樣的錯誤。

後來查了一下這個專案的參考項目,發現不知道為啥有裝了這個套件,本來以為是這個問題,但移除之後,還是有相同的問題。

image

既然如此,就去Web.config查吧,最後終於發現少了這一行。

<add key="webpages:Version" value="1.0.0.0"/>

後來把他補上去後,重新載入專案後,就可以了 ( 以下是要塞入的位置 )

<configuration>
  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <connectionStrings>

至於為什麼會少,老實說,已經年代久遠,無可考了,總之就在這邊紀錄一下吧。