顯示具有 WinCE AP 標籤的文章。 顯示所有文章
顯示具有 WinCE AP 標籤的文章。 顯示所有文章

2008年3月3日

仿HTC介面軟體:HTC Cube OpenGL

Basic Navigation:


Adding/Removing a Contact:

##CONTINUE##
Button Functionality:


程式發表區:http://forum.xda-developers.com/showthread.php?t=358102

2007年10月8日

Display PNG file in WinCE 5.0







PNG圖檔支援背景透明的效果,不過一開始使用時,卻發現原本應該是要透明的背景,卻仍然顯示出來,這樣在將來若做UI介面時會使的美觀上大打折扣

##CONTINUE##
後來在書上發現,可以利用程式來自行處理,不過,處理時必須要指定要變為透明的顏色,也就是說,每載入一張PNG圖都必須去取得透明色的RGB值,才能將它變為透明,這樣會使得設計上非常不方便,同時,在處理後的圖示上,由於只譨指定一種顏色為透明,因此,若圖示上有陰影的效果,會使得圖示的邊緣處理的不漂亮!







後來,發現在WinCE 5.0上其實有提供透明背景顯示,不過需要加入Component後才行,可以在platform builder上搜尋SYSGEN_GDI_ALPHABLEND,加入"Alphablend API",重新Build image後即可!







至於顯示PNG的方便,有很多library可以使用,不過還需要時間比較一下,微軟也有提供
IImage class可以使用。


CoInitializeEx(NULL, 0);
IImagingFactory* pImageFactory;
IImage *pImage = NULL;


HRESULT hr = CoCreateInstance(CLSID_ImagingFactory, NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IImagingFactory),
(LPVOID *)&pImageFactory);

// Load image from file
pImageFactory->CreateImageFromFile(L"info.png", &pImage);

// Get image information
ImageInfo info;
pImage->GetImageInfo(&info);

RECT rc={0,0,info.Width, info.Height};

pImage->Draw(dc, &rc, NULL);

// Clean up
pImage->Release();
pImageFactory->Release();

CoUninitialize();

2007年10月1日

修正Reset Registry to default問題

藉由更動TOC中變數來判斷是否要將系統回復為預設值

AP部分:將TOC中bReserved[3]的值設為0X45

TOC *p;
BYTE InBuf[2048];
DWORD psize,val=0;
if(::KernelIoControl(IOCTL_READ_TOC, NULL,0,&InBuf, 2048,&psize))
{
p = (TOC *)InBuf;
p->bReserved[3] =0x45;
::KernelIoControl(IOCTL_WRITE_TOC, &InBuf, 2048,NULL,0,&psize);
KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL); //reboot device
}


##CONTINUE##
Driver部分:

  • 在IsAnyKeyDown()加入判斷:若值為0x45則將系統回復為預設值

if(toc->bReserved[3] == 0x45)
{
RETAILMSG(1, (TEXT("#####toc->bReserved[3]=%d \r\n"),toc->bReserved[3]));
return TRUE;
}
.........


  • 在XXXDaemon中加入判斷:若值為0x45,則將PETestFolder刪除,並將值設為0避免重複作回復預設值的動作!

if(toc->bReserved[3] == 0x45)
{
if(::KernelIoControl(IOCTL_READ_TOC, NULL,0,&InBuf, 2048,&psize))
{
p = (TOC *)InBuf;
p->bReserved[3] =0;
::KernelIoControl(IOCTL_WRITE_TOC, &InBuf, 2048,NULL,0,&psize);
}
hFind = FindFirstFile (L"\\My Flash Disk\\PETestFolder", &FindFileData);
if(hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
if(EmptyDirectory(_T("\\My Flash Disk\\PETestFolder"),TRUE))
{
RemoveDirectory(_T("\\My Flash Disk\\PETestFolder"));
}
}

2007年9月20日

[轉貼]滿街都是iPod跟iPhone‧漫談UI界的逆向工程

出處:HandyUI.com
作者:陳文剛


逆向工程(Reversed Engineering)普遍存在於各個領域,尤其在台灣,各行各業的高手們,更是樂此不疲。大廚師喜歡到處吃吃喝喝,用舌頭跟鼻子去破解各地美食的料理秘方;電影工作者喜歡把經典橋段拿來重複播放、快轉倒轉、慢動作格放,反覆地推敲每一個走位跟運鏡。就連裕隆老總嚴凱泰都曾發生過類似的趣事,他在正式代理Armani前,就曾經把Armani西裝丟給港台一流的打版師傅拆解研究,直到怎麼組都組不回原樣時,他才心甘情願地放棄自行生產,專心做代理銷售。

每個人看到好東西時,心裡自然都會想著:「媽阿,這是怎麼辦到的?」也因此,人們都會渴望把美好的東西拆解,把它的外表一層一層地撥開,直到搞清楚這是怎麼一回事為止。這個過程就像拆禮物一樣,一層一層的包裝被打開,外觀越來越接近物品本身應有的大小跟重量,最後露出禮物的一瞬間,謎底終於揭曉,這可是相當迷人的經驗。「喔,原來是這樣做的阿!」這樣的讚嘆聲,就在最終破解的那一刻,發自內心地冒了出來。人類最原始,那種窺探、追根究底、搞懂怎麼做的本能渴望,就在這樣的過程中,一次又一次地被徹底滿足。


##CONTINUE##
就像上面所提到的,逆向工程的過程裡,充滿了驚喜與刺激,既知性,又充滿挑戰性。不過,從 UI Design的角度來看,搞懂怎麼做(know-how),跟知道為什麼要這樣做(know-why),其實是天差地遠的兩件事。

在UI界,逆向工程這檔子事也是常常在發生,每天都在做,只是抄得多抄得少,或是依賴程度高低的差別而已。設計手機介面的時候,拿起Nokia或是Sony Ericsson玩看看,參考一下人家輸入法是怎樣做的;或是設計相機時,拿起 Canon或Nikon,看看人家的人臉對焦框是方的還是圓的,合焦時會不會變色?久而久之,所有類似產品的介面都長得很像,用起來都一樣,沒有特別好,也不會特別差。由於這種狀況每天都在發生,所以部分的介面設計師,很可能已經習慣於大量地參考別人,然後小幅地改善自己。



從模仿中學習,其實是個必經的歷程

從現有案例中學習,其實是件好事,也或許可以當作是蹲馬步般的基本功。舉個例來說,要一個沒吃過義大利菜的人,做出好吃的義大利式燉飯 (Risotto),或是要一個沒玩過遊戲軟體的人,憑空設計出一款多人線上角色扮演遊戲 (MMORPG),那都是相當困難,甚至天方夜譚的事。

介面設計師在開始著手設計前,當然要對該產品,或是同一領域的其他產品,有清楚的認識。在介面設計流程裡,這個知己知彼的過程與方法,就叫做競爭者分析 (Competitor Study)。通常在做產品定位,或是進行設計前,都會先跑過一次分析,搞清楚現有產品的優勢劣勢,以及自家產品的機會點。

在做介面設計的競爭者分析時,最簡單的方法是,找來各家產品,快速比較一下設計風格、資訊架構、互動效果等,一個表格或是幾張slide大概就可以搞定。另一種比較嚴謹的做法則是,把整個介面設計的元素全部拆解開來,重製出一份UI flow,並且將layout跟icon全部攤開,把各種互動設計都分門別類,一個一個做比較分析。後者的做法,跟所謂的逆向工程,其實沒什麼兩樣。

經過上述的拆解與分析之後,簡單如iPod,複雜如iPhone,內部的操作流程跟介面設計元素,都可以攤開來一覽無遺。這時候要抄要改,幾乎都像扒滷肉飯一樣輕鬆 (其實也沒這樣輕鬆,苦工夫一堆,又會被告,千萬別傻傻地去做)。至於要參考哪個部分,如何轉化成自己的設計,則完全看設計師自己的功力與經驗。

就像前面舉做燉飯,或是研發線上遊戲的例子一樣,做介面設計時,要是不做點競爭者分析的功課,就很可能會閉門造車,搞出類似重新發明輪胎的糗事 (歷史上,輪胎的外型曾經被重新發明很多次,方型的,雪橇型的都有,但是弄到最後,事實證明還是圓的最有效率)。透過逆向工程的手段,去快速學習、了解競爭者特性,是非常有效率且必要的做法。莫內、梵谷、畢卡索,哪一個沒有畫過靜物素描,沒有揣摩過大批翻製的石膏像?從模仿中學習,是人類進步的重要技能,在科技快速發展的今天,更是得不停地模仿,不停地踩在別人既有的基礎上,追求實質的進步。



掌握關鍵本質,才能夠舉一反三

只不過,模仿應該只是手段,而不是最終目的;知道如何做得一模一樣,跟了解背後的原理原則,真的是天差地遠的兩件事。

舉個實際的例子來說,有時候我們常會看到許多四不像的產品規格,去找PM討論時,總會聽到:「XX大廠就是這樣設計的,我想他們這樣做,一定有他的原因跟道理,我們照著這樣做比較安全。」 更厲害的PM則會融會貫通、旁徵援引,說出一套道理來:「我會想拿掉電源開關,是因為iPod也沒有電源開關;至於這裡要長按兩秒鐘,是因為PDA也都是長按兩秒鐘;而且我還加了閃七下的燈號提示,這是我們自己發明的,非常friendly,跟Canon的印表機有異曲同工之妙。」

這樣噴飯的對話常常出現,每回聽到這些謬論,除了心裡苦笑之外,也很懶得去反駁。老實說,我不太能夠接受「XX大廠這樣設計,一定有他的原因跟道理」這種說法,太籠統,而且也太馬虎行事。在搞不清楚別人為什麼這樣設計之前,就一股腦地抄,抄到最後就像拼裝車一樣,東拼西湊,重看不重用。

好的介面設計師不只懂得欣賞好產品,具有一眼就看出關鍵概念的鑑賞力,而且更懂得將這些精采地設計概念消化吸收,重新轉化成新的設計,比過去看過的更精練,更貼近使用者需求。夠水準的介面設計師,絕對不會只從Apple, Nokia等公司產品找靈感,更大一部分的啟發來自於日常生活,來自於人類歷史當中所有的經典設計。

舉個例來說,在思考手寫輸入介面的可能性時,我們會去參考Windows Mobile、漢王、蒙恬,或是甚至是iPhone的觸控螢幕鍵盤。但是在此同時,我們更關注的是,手、筆跟紙的關係。我們觀察人們長久以來怎麼樣用筆紀錄,如何在紙張上頭註記,如何塗改,如何銷毀。漸漸地會發現到,現有的手寫輸入介面都不夠好,連市面上最棒的產品也頂多在及格邊緣,離感動人心還差的遠。這時候,精采的就來了。從競爭者分析中看到現況,找到機會,然後透過設計師的經驗與巧思,就有可能設計出一套全新的手寫輸入介面,一舉超越現下的所有產品,或者你要說是,有史以來的所有產品也可以。

這就是具備鑑賞力、觀察力,並且掌握關鍵本質的奇妙功效。同樣是做競爭者分析,同樣是逆向工程,不明就裡地抄,跟了解原理原則後的全新設計,很可能就是地獄與天堂的差別。在這一點上,台灣廠商的逆向工程技術確實很先進,但是少了創意,少了理想與堅持,最後很可能開發出的全是一堆me too,或甚至比me too還差的產品,真的是很可惜。

2007年8月2日

Something about including managed code to OS Image

在MSDN上提到:
The MODULES section specifies which Windows Embedded CE-based modules are included in the run-time image, and how they are loaded into the memory table as established in the MEMORY section of the Config.bib file.

This section can contain up to 2,000 modules, which consist of a two-part combination of source code and data.

Note:
Do not include managed code in the MODULES section. This is because the kernel does not load managed code. Instead, managed code is opened as a memory-mapped file by the .NET Compact Framework. Managed code must be included in the FILES section.

##CONTINUE##
至於甚麼是Managed Code? Unmanaged Code? Native Code?可以參考這篇文章!Managed, Unmanaged, Native: What Kind of Code Is This?

因此,在platform.bib中,必須將要加入的Managed Code加在Files Section而不是在Modules Section!

2007年7月24日

在WinCE桌面上加個程式捷徑

##CONTINUE##
1.產生一個.lnk檔案

產生一個.lnk檔案,例如:MyApp.lnk,檔案內容為

20#"\Windows\MyApp.exe"

其中,20代表#後的字串個數,包含""!

並將.lnk檔放到%_PROJECTOAKROOT%\Files目錄下!

2.在.dat內加入捷徑宣告

在project.dat內加入下面宣告:

Directory("\Windows\Desktop"):-File("DebugZoneAp.lnk", "\Windows\DebugZoneAp.lnk")

3.將.lnk檔增加到ROM Image內

在project.bib之FILE區內加入:

DebugZoneAp.lnk $(_FLATRELEASEDIR)\DebugZoneAp.LNK NK S

2007年7月8日

HOW TO:進行對 Windows Form 控制項的安全執行緒呼叫

Windows Form 控制項的存取並非原本就採用安全執行緒的方式。如果您有兩個或多個執行緒管理控制項的狀態,就有可能強制控制項進入不一致的狀態。其他與執行緒有關的錯誤 也有可能如此,包括競爭情形和死結。確定存取控制項是以安全執行緒的方式來進行,是很重要的。
##CONTINUE##
對 Windows Form 控制項進行安全執行緒呼叫
若要對 Windows Form 控制項進行安全執行緒呼叫

1.查詢控制項的 InvokeRequired 屬性。
2.如果 InvokeRequired 傳回 true,就使用對控制項進行實際呼叫的委派 (Delegate) 呼叫 Invoke。
3.如果 InvokeRequired 傳回 false,便直接呼叫控制項。

private void setTextSafeBtn_Click(
object sender,
EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));

this.demoThread.Start();
}

// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
private void ThreadProcSafe()
{
this.SetText("This text was set safely.");
}
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
}
資料來源:MSDN

2007年6月23日

Windows Form vs Multithread

最近試著用C#練習寫BT(bluetooth)搜尋程式,為了讓搜尋時視窗不要因為搜尋時而導致視窗無法移動,因此,最簡單的方式,就是在增加一個thread來處理搜尋的動作,等處理完後再將結果顯示在ListBox上:

##CONTINUE##

public void Search_Click(object sender, EventArgs e)

{
this.listBox_devices.Items.Clear();
this.Text = "Search Bluetooth Device...";
this.search_thread = new Thread(new ThreadStart(search));
search_thread.Start();
}

private void search()
{
this.listBox_devices.Items.Clear();

InTheHand.Net.Sockets.BluetoothClient bc = new InTheHand.Net.Sockets.BluetoothClient();

InTheHand.Net.Sockets.BluetoothDeviceInfo[] array = bc.DiscoverDevices();

for (int i = 0; i <>

this.address_array[i] = array[i].DeviceAddress;
this.listBox_devices.Items.Add(array[i].DeviceName);

}

}

上面程式在按下Search按鈕後將會啟動Search thread處理搜尋的功能,搜尋完後會將蒐尋到的BT Devices的名稱儲存下來並顯示在ListBox中,看起來似乎沒甚麼問題,但程式在按下Search按鈕後程式就當掉了!

原來問題在於,只有建立Windows Form的thread才能存取、修改Form或控制項的內容,因為.NET的控制項在設計時是執行緒相依(thread affnity),只有在建立該Form或控制項的執行緒才能安全地存取其屬性。



當控制項的狀態改變時,系統會把它轉換成視窗訊息,放到訊息佇列中(Message Queue),再由程式處理!

不過,將訊息放入訊息佇列(Message Queue)的方式分為兩種,一種為SendMessage(),一個則為PostMessage()。前者為呼叫者會停住直到訊息被處理為止;而後者呼叫端則是將訊息放置訊息佇列後即立刻返回。

而在.NET裡,所有Form或是控制項的屬性變更,皆由SendMessage()送出訊息!

因此,在上面的程式中,當主執行緒等待搜尋執行緒完成,而搜尋執行緒因為嚐試更新控制項,因此呼叫了SendMessage(),而SendMessage()會因此使搜尋執行緒停住,因為它必須停主執行緒將SendMessage()送出的訊息處理,而主執行緒也在等待搜尋執行緒執行完畢,因此變成互相等待的情形,程式因此當掉了!


2007年6月8日

C# : Delegate(委派)

用來宣告委派 (Delegate)。委派是一種參考型別,它參考型別的 Shared 方法或物件的執行個體方法 (Instance Method)。任何具有相符參數型別和傳回型別的程序都可用來建立這個委派類別的執行個體。接著可透過委派執行個體來叫用程序。
##CONTINUE##
Delegate 陳述式定義委派類別的參數型別和傳回型別。任何具有相符參數型別和傳回型別的程序都可用來建立這個委派類別的執行個體。接著可透過委派執行個體來叫用程序,方式是呼叫委派的 Invoke 方法。

~MSDN

Delegate(委派)大致類似 C++ 的函式指標(Function Pointer),函數指標的致命缺點是:無法對參數 (parameter) 和返回值 (return value) 的型態進行檢查,因為函數已經退化成指標,指標是不帶有這些型態資訊的。少了型態檢查,當參數或返回值不一致時,會造成嚴重的錯誤。編譯器和虛擬機器 (VM) 並不會幫我們找出函數指標這樣的致命錯誤。所以,許多新的程式語言不支援函數指標,而改用其他方式。

至於為什麼會需要function pointer、delegate機制呢?簡單的想法:『為什麼我們不能將function也如同變數一樣傳進另外一個function呢?』,C語言的解決方式是,利用pointer指向該function,將該pointer傳入另外一個function,只要將該pointer dereference後,就如同存取原function一樣。C#解決的方式是,將function包成delegate object,傳入另外一個function。

參考" Function Pointer、Delegate和Function Object (初級) (C/C++) (OO C++) (Template C++) (C#)"

2007年6月4日

Visual Studio 2005試用

##CONTINUE##
最近重新安裝Visual Studio 2005再試用一下,之前使用的時候,總是無法順利的部署到機器上,這次到網路論壇上找了一下,發現原來之前安裝的順序錯了,正確的安裝順序應該是:
1. 安裝Visual Studio 2005
2. 安裝裝置的SDK
3. 在Visual studio 2005的選單上,選取"工具\連接到裝置",選取要連結的裝置即可,例如SNAXXXX

接下來就可以開啟新的專案來開發新的Ap了,試用C#寫了一個簡單的Ap確實可以在760上Run,不過第一次部署時,花了不少的時間安裝檔案,還目前還不清楚需要哪些檔案才能執行?

2007年3月15日

wince下加載驅動程式

加載流驅動程序有三種方法:

第一種加載類型是在系統啟動的時候進行的。當Winows CE的平台啟動的時候,設備管理器(Device.exe)從註冊表的HKEY_LOCAL_MACHINE\Drivers\RootKey下面加載入口點,通常RootKey的值都被設置為Drivers\BuiltIn。然後設備管理器(Device.exe)通過\RootKey提供的入口點開始讀取 HKEY_LOCAL_MACHINE \Drivers\Builtin的內容,並加載已列出的驅動程式。
##CONTINUE##
第二種加載的類型是在設備管理程式自動檢測外圍設備設備與基於Windows CE平台的連接時進行的。

第三種加載類型是當設備管理器程序不能夠自動檢測或加載某一種驅動程式的時候,這個時候的可以使用系統提供的函數ActivateDeviceEx函數來加載驅動程序。

HANDLE ActivateDeviceEx(
LPCWSTR lpszDevKey,
LPCVOID lpRegEnts,
DWORD cRegEnts,
LPVOID lpvParam
);
lpszDevKey :[HKEY_LOCAL_MACHINE]下的登錄機碼名稱
lpvParam:傳送至驅動程式的Init函式中的指標。
傳回值:裝置的控制碼,可用來卸載Driver時傳送之參數!

以PCT661的PowerButton Driver為例:

方法一:
若在Platform.reg中已經有定義相關資訊,則必須在相關設定中加入"Flags"的參數,並將值定為4

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PWRBUTTON]
"Prefix"="PWR"
"Dll"="PwrButton.Dll"
"Order"=dword:2
"Ioctl"=dword:4
"KeyMuxTime"=dword:64 ; 100 ms
IF BSP_ATLAS_KEYPANEL_V3
"KeyMuxValue"=dword:C3 ; VK_APP3
ELSE
"KeyMuxValue"=dword:d ; VK_RETURN
"Flags"=dword:4


Flags設定為4表示系統開機時不去載入此driver!
有關Flags參數設定,可參考MSDN裡ActivateDeviceEx()說明!

接著就可以在AP中呼叫ActivateDeviceEx()
Step1 :
呼叫前須先將"Flags"的值設為0,Driver才能成功被載入:
if(RegCreateKeyEx( HKEY_LOCAL_MACHINE,szPWRBTNDevKey,0,_T("PWRBUTTON"),REG_OPTION_VOLATILE,0,NULL,&hKey,&dwDisposition) == ERROR_SUCCESS)
{
DisplayData(TEXT("RegCreateKeyEx Success"));

val = 0; RegSetValueEx(hKey,_T("Flags"),0,REG_DWORD,(PBYTE)&val,sizeof(DWORD));
RegCloseKey(hKey);
}
Step2 :
呼叫ActivateDeviceEx():
TCHAR szPWRBTNDevKey[] = _T("Drivers\\BuiltIn\\PWRBUTTON");
hDev = ActivateDeviceEx( szPWRBTNDevKey, NULL, 0, NULL );


方法二:
若沒有在Platfom.reg中設定Registry相關資料,則必須在載入前於Registry自行加入相關設定:

if(RegCreateKeyEx( HKEY_LOCAL_MACHINE,szKeyPADDevKey,0,
_T("KEYPAD"),REG_OPTION_VOLATILE,0,NULL,&hKey,&dwDisposition) == ERROR_SUCCESS)
{
RegSetValueEx(hKey,_T("Prefix"),0,REG_SZ,(const BYTE*)TEXT("PWR"),sizeof(TEXT("PWR")));
RegSetValueEx(hKey,_T("Dll"),0,REG_SZ,(const BYTE*)TEXT("touchpad.dll"),sizeof(TEXT("PwrButton.dll")));
val = 4;
RegSetValueEx(hKey,_T("Ioctl"),0,REG_DWORD,(PBYTE)&val,sizeof(DWORD));
val = 100;
RegSetValueEx(hKey,_T("KeyMuxTime"),0,REG_DWORD,(PBYTE)&val,sizeof(DWORD));
...............
RegCloseKey(hKey);
}
接著一樣再呼叫ActivateDeviceEx()

若想卸載Driver,則可以呼叫DeactivateDevice()

DeactivateDevice(hDev);
hDev為ActivateDeviceEx()之傳回值

問題:

* 有些Driver無法成功載入,如Bluetooth
* 有些Driver只能載入一次,卸載後無法再載入第二次,例如KEYPAD