大約在六月中到八月左右,小弟有緣用C#寫了一個跑在PocketPC上的程式,由於火候不佳整體結果差強人意,還好最後有完成要求!但程式架構超醜的…
在編程的過程中,深刻體認到某位前輩所說的「與一般的C#同中有異」,也真正感覺到有一些灰色地帶,所幸山窮水盡疑無路,柳暗花明又一村,一些大大小小的難關都過去了。所以略為筆記一下這一段日子習得的東西。
整合環境
ppc的視窗很小,我用的機器螢幕甚至不是標準型,要完整呈現豐富的UI略有困難。整合環境下發生過最難以理解的"feature"就是,如果將一個控制項移到某一個Panel的上空,則控制項新 parent 就會變成該Panel。這在使用Panel管理UI的顯/隱形時,不止一次製造了困難與笑料。
雖然是十分合理的設計,但我常常忘記這個效應是存在的。
視窗按鈕
關於這個 issue 請參見下面 MSDN 文章要小心使用者被卡在奇怪的無間地獄裡!
這篇文章裡也提到了原生GDI API的速度是多麼的快啊…
'using'
在using這個敘述句開始時配置的資源之生存範圍僅限其後的Block,超過後系統會回收資源。這有兩個重要用處,其一是運用GDI resources時,建議gc回收這些寶貴的GDI Objects。
另一個是 用在File IO,File被視為unmanaged resources,故讀寫時應該將整組I/O的程式碼都包在一個using敘述裡。在我的經驗裡,沒有使用using述句的程式碼總是會碰到奇怪的File locking問題,包進using敘述句中自動解決。
使用gif/jpeg圖檔
這是一個經常碰到的問題,原始的 .Net CF Framework僅支援使用點陣圖,沒辦法處理GIF與JPEG格式的檔案。解決之道是使用SHLoadImage()這個API函數,它支援從檔案系統中讀.gif/*.jpg的檔案。再透過Image類別的FromHbitmap()方法就可以將圖檔內容塞到Image物件裡。Image.FromHbitmap()是.Net CF 2.0後才多出來的功能,小弟有幸是在.Net CF 2.0上開發,假如是.Net CF 1.x就必需自己撰寫額外的程式碼處理了。
從一些VS.Net裡頭的標頭檔看起來,如果採用C語言開發,預設需引入的標頭檔裡似乎就有這個函數;然而我一開始照著標頭檔裡的呼叫慣例編寫成C#的版本卻是失敗的,後來拜Google拜了一晚才找到一個大神分享的版本,原來EntryPoint改成"#75"就會動了…看起來,這個問題似乎只有觀察aygshell.dll是如何export裡頭的函數才能得到解答了。
不同平台上採用的aygshell.dll實際上是不同的檔案,(雖然它們都會叫同一個名字)拜一下Google應該有辦法找到一包壓了眾多不同版本的aygshell.dll的壓縮檔。小弟開發時的實機是HP iPAQ系列,也許不同的實機,要求的EntryPoint設定也不一樣。
下面野人獻曝一下,是一個簡單的API Wrapper Class,有任何值得改進之處,還請不吝指教。
class SHLoadImageFileWrapper
{
[DllImport("aygshell.dll", EntryPoint = "#75", SetLastError = true)]
public static extern IntPtr SHLoadImageFile(string szFileName);
[DllImport("coredll.dll")]
static extern bool DeleteObject(IntPtr hObject);
public static Image LoadImage(string fname)
{
FileInfo fil = new FileInfo(fname);
Image img = null;
if (fil.Exists)
{
IntPtr handle = SHLoadImageFile(fil.FullName);
img = Image.FromHbitmap(handle);
DeleteObject(handle);
}
else
{
throw new FileNotFoundException("In SHLoadImageFileWrapper.LoadImage: FileNotfound");
}
return img;
}
}
