Windows CE Development Notes/zh TW

From Lazarus wiki
Jump to navigationJump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
WinCE Logo.png

This article applies to WinCE only.

See also: Multiplatform Programming Guide

English (en) 中文(台灣)‎ (zh_TW)

為您的程式進行偵錯

請參考[這裡]的說明 (中文)。

  • 有時候GDB程式可能會死掉,請直接把偵錯程式停止,然後重來一次吧。
  • 如果您打開了呼叫堆疊(call stack)子視窗的話,他會占用很多資源,所以當您進行偵錯的時候速度會很慢,有時候也可能讓偵錯程式死掉,所以請注意,沒必要的時候不要打開這個子視窗。
  • 請在您需要中斷程式的部分設定breakpoint(中斷點),否則您可能沒辦法在需要程式暫停的時候讓它乖乖停止。
  • 除非是要作偵錯,不然請別對您的程式進行反組譯或逆向工程,因為這些strip的工具程式或多或少都有些問題,拆解過以後,您的程式可能會沒辦法執行,所以不建議您使用它。
  • 有時候單步執行會用很久的時間,要請您多準備些耐心,我曾經要透過偵錯程式做個簡單的單步執行,結果就花了一分多鐘…

資料存取不一致的問題

在使用ARM處理器的時候,有時會遇到EBusError的另外狀況,當時的訊息可能是資料存取不一致 (misaligned data access),以下的幾個章節會說明它發生的原因跟解決的方法。


甚麼是”資料存取不一致”?

假設CPU到記憶體的匯流排(Bus)是8bit,而您想讀取一個Byte。既然您的Bus是8bit的,就可以對每一個Byte的定址定的清清楚楚,那麼一次讀取一個byte就一定沒有問題。現在請想像一下,一個使用32bit匯流排的CPU要讀取一個Byte。32bit的匯流排,每次讀取的資料都會是一致的長度,也就是32bits (=4bytes),定址的時候也是一樣,都是以四的倍數進行定址的,所以要得到CPU真正想讀取的資料時,CPU就會把右邊的byte進行搬移。

好的,現在我們再想想,在讀取一個32bits的整數時,在一個8bits的CPU上面,必須要讀四次,每次讀一個byte,才能讀到一個32bits的整數,在32bits的CPU,如果定址也正好是4bytes的倍數,則相同的動作只要讀一次就行了。如果不是的話,就得把32bits整數分拆成不同的部分讀取,然後再組合成一個整數,在x86系列的CPU上面就是這麼作的,所以是比較沒效率的。 在SPARC跟ARM系列CPU的一些分支上面(*)就不支援這種分拆讀取再組合的動作,它們會直接回報出一個匯流排錯誤,錯誤訊息就是”資料存取不一致”。

(*)有些以ARM為基礎的CPU已經作了功能補強,把這問題給處理掉了,但這要看是哪個製造商製造的ARM處理器,還有它們的規格書上面是否有註明已經作了這問題的修補。


如何解決這個問題呢?

在對指標進行轉型(typecasting)的時候,一定要很小心。16bit (2bytes)長的資料跟32bit (4bytes)長的資料一定要在記憶體裡面轉成4bytes長的資料,不然這個bus錯誤就會發生了。 或者在使用到這樣的轉型動作之前加上一個新的關鍵字 (unaligned),這個關鍵字可以同時放在一個語法描述的左邊跟右邊。

例如:

var
p1:^Longint;
l:longint;
begin
p1^:=20;  //這個assignment可能會造成bus error, 如果p這個指標正好指向了一個沒對齊的記憶體位址,例如: 該位址不是四的倍數。
unaligned(p1^):=20;  //這樣就沒問題
l:=pl^;  //這也可能會造成問題
l:=unaligned(pl^);  //加個關鍵字就保險了
end.

在使用Pascal的自訂形別:Pack record時,編譯器會自動把對該record的所有成員的所有動作都定義成unaligned存取。目前,有時在循環使用到pack record的時候(有人翻成巢式定義),編譯器不會自動把需要的程式碼建立出來,所以這時候我們就得自己加上unaligned關鍵字了。 但是請留意啊! 循環使用pack record來定義新資料結構,而且對它所有成員的存取都加上unaligned時,會對程式處理資料的速度造成很大的影響。 所以非必要時,別這麼用吧。

實現分頁控制項(Tab Controls)的細節(TPageControl)

絕大多數的控制項在移植到WinCE的時候,都是直接把Win32的原始碼拿來稍微改一改而已,但是分頁控制項在WinCE上面要實現,比Win32平台上難得太多了。

簡單的說,有以下這幾個難處:

  • 不支援縱向文字,所以分頁控制項的分頁標籤如果放在左邊或右邊,文字就沒辦法顯示了。
  • 由於還沒釐清的原因(是WinCE的錯誤嗎?),分頁控制項的分頁標籤放在畫面上方的時候,分頁標籤上的文字也不會顯示出來。

此外,微軟也建議在Windows CE裡面使用分頁控制項時,使用分頁標籤位於畫面下方的樣式,這樣使用者在用手切換分頁的時候就不會遮到觸控螢幕了。綜合上述援因,我決定把Windows CE版本的分頁控制項寫死成只有一個樣式,這是跟其它控制項最大的不同。 預設的樣式看來有點老式,但我發現新的樣式太簡化了。雖然樣式有點老式,但您還是可以一眼就看出它是個分頁控制項,如果您想設定分頁控制項的樣式(設定為平滑樣式: flat)的話,請從程式碼裡面直接控制(TWinCEWSCustomNotebook.CreateHandle),要改變它的外觀也並不難。

您也可以從這裡參閱相關文件: http://msdn2.microsoft.com/en-us/library/aa921319.aspx

背景跟表單位置的問題

每一頁的背景之間是不會自動被更新的,且因為控制項的背景邊框很細,而且並不完整(不是每一邊都有邊框的),有時使用者就可以這樣看到表單的背景了。

我使用了個不錯的方法,把WinCE的表單背景作了些處理,細節請見: http://www.pocketpcdn.com/forum/viewtopic.php?t=499

在沒有進行表單位置調整前,分頁控制項看起來像這樣:

Before tab adjust.png

調整完以後,看起來會像這樣:

After tab adjust.png

請注意,在沒有調整之前,您可以看到控制項後面的表單背景,但是在調整過以後,很明顯的就看不到了,因為我使用了TPanel控制項來調整控制項的位置。

我不確定用固定的背景色是不是個好主意,或者應該用哪個固定的顏色,所以我把這個問題留到現在還沒解決。

仍在偵錯中的項目

已知的問題跟錯誤

SetProp - GetProp - RemoveProp APIs

Windows CE沒有SetProp跟GetProp這兩個很常用的API,所以我已經自己製作/模擬了類似動作。 目前我製作的動作跟Win32 API並不完全一樣,在Win32裡面,我們可以對每個視窗,一次設定多個不同名稱的屬性,但我在實現這功能的時候,把名稱給省略了,所以我們只能對每一個控制項中,指定的同一類屬性進行設定。(要改成跟Win32的作法一樣也不難,但我發現目前這麼作沒甚麼幫助) 而removeprop這個功能也還沒被使用過。 所以在您離開應用程式的時候,可能發生記憶體裂縫。(我不確定WinCE是否會自己釋放記憶體空間,或者在Windows Handle被釋放時同時釋放記憶體)這部分會很快就被實現的。


LCLControlSizeNeedsUpdate LCLBoundsToWin32Bounds LCLFormSizeToWin32Size GetLCLClientBoundsOffset GetLCLClientBoundsOffset

這部分我還沒驗證過,我也不覺得這幾個元件會像我們在Win32平台上那麼需要它們。所以還需要重新設計,舉例來說TWinCEWSWinControl.SetBounds,我就把裡面的movewindow給拿掉了,因為在WinCE上面也不知道能把它移到哪兒去。

Brushes

在WinCE裡面也沒有Brush,我已經把CreateBrushIndirect直接對應到CreateSolidBrush跟CreateDIBPatternBrushPt了,如果在LCL裡面用到其它的flag的話,就會出錯喔。

其它

一些有用的資訊:

External signal(?) Error

有時候您可能會在偵錯程式裡面看到這個訊息,表示出現了”資料存取不一致”的問題,正常狀況下應該不會發生的。 您可以在出錯的原始碼指令檔裡面加入”unaligned”這個關鍵字,這個錯誤會發生在所有可能出問題的地方。


Menus

這需要大規模的工程,需要對LCL如何處理Menu的背景知識有稍微深入的了解,或許還需要稍微修正一下該架構。


未來的工作

  • 要確認WinCE版本的WinAPI相關描述,目前使用到的部分跟Win32還大致相同,僅有少數情形是不同的。
  • 目前用Lazarus跟WinCE介面編譯出來的應用程式都是經過最佳化的,並且只能在PocketPC裝置裡工作。

連結

以下是建立Windows CE介面時,有幫助的幾個連結: 如何將您的Win32程式移植到Windows CE

一些舊文章,說明在建立WinCE控制項的時候需要使用到的參數

詳盡說明了WinCE參數的相關網頁

把應用程式的選單移植到CE的使用者介面裡

一般Win32-API跟Windows CE之間的差別

資源定義的指令

GUI控制項樣式

要開發高解析度WinCE應用程式控制項的注意事項

將KOL GUI 函式庫移植到WinCE上面