WinCE驅動開發問題精華集錦-2
摘自:
http://hi.baidu.com/mcu%5Fspaces/blog/item/f14d1d2af1a2e33c5243c144.html21、 文件格式如下所示,我想把每行的4個值讀到4個變量中,用EVC如何編程? 第一行: 460.000, 3384672.357342, 521268.972763
第二行: 475.117, 3384663.772419, 521281.415271
偽代碼如下:
FILE *stream;
stream = _wfopen(L"\\a.txt", L"r+");
if( stream == NULL )
return;
fseek(stream, 0L, SEEK_SET );
while( !feof( stream ) )
{
fwscanf(stream, L"%s", WCHAR1);
fwscanf(stream, L"%f", float1);
fwscanf(stream, L"%f", float2);
fwscanf(stream, L"%f", float3);
}
fclose( stream );
22、GWES組件的功能有哪些? GWES不僅負責GDI、窗口、消息,還負責管理本機設備驅動程序,負責加載顯示、鍵盤鼠標、觸摸屏驅動程序,而且GWES本身包含電源、LED驅動程序。
23、如何在PB中預先設定好存儲內存和程序內存的大小,我想多劃分一些空間給程序內存? 兩種辦法:
1)、在定制內核時在config.bib文件中設置FSRAMPERCENT = number,具體number可參考標題為“FSRAMPERCENT ”的幫助文檔。這種辦法是修改內核的設置,所有一直有效。
2)、在應用程序中調用API SetSystemMemoryDivision,如果函數返回SYSMEM_CHANGED表示成功,如果返回SYSMEM_MUSTREBOOT表示需要熱啟動才能有效。這種辦法需要每次啟動后調用API才有效。
24、 如何取消鼠標光標? 通過取消SYS變量來實現此目的,在PB命令行下鍵入“set SYSGEN_CURSOR=”,然后回車確認。
25、EVC下調用TextOut如何編譯會出錯? 類似這樣的問題很多,這是因為EVC的幫助文檔內容有錯誤。可能EVC的幫助文檔內容是從桌面Windows幫助文檔復制過來的,所以很多API函數還有例子代碼都有錯誤,例如幫助文檔中包含一個API函數的說明,但是實際編譯的時候提示沒有這個API,有的例子代碼采用ANSI字符串,而WINCE的API都是寬字符版本,造成直接復制過來編譯失敗。
因為MFC for WINCE的CDC類中沒有TextOut成員函數,所以編譯會出錯,可以用其它類成員函數ExtTextOut或者DrawText替換。
26、我如何將我的dll軟件讓現有的ce系統認可?盡管我也知道應該使用signfile.exe程序進行簽名,但是我并不知道那個ce系統認可的簽名應該是啥
如果你說的WINCE系統內核已經加入了簽名認證機制,那么沒有私鑰對你的DLL文件簽名肯定是無法運行在此內核中的,一般簽名密鑰的密鑰長度都是1024位,很難破解。
27、如果查看WINCE注冊表中的內容? 兩種辦法:
1)、建立同步后,用EVC自帶的工具“Remote Registry Editor”打開查看。
2)、從網上下載注冊表查看工具,放到WINCE設備中。
28、調用directshow出現鏈接錯誤,如何解決? player.obj : error LNK2001: unresolved external symbol _IID_IVideoWindow
player.obj : error LNK2001: unresolved external symbol _IID_IMediaControl
這是因為鏈接器沒有找到合適的.lib文件。兩種辦法:
1)、在EVC菜單Tools—options—directories 里把library files的路徑重新調整一下。如果你只安裝了EVC自帶的Standard SDK而沒有其它SDK,可以指定WINCE目錄中的.lib文件路徑,例如D:\WINCE500\PUBLIC\DIRECTX\OAK\LIB\X86\RETAIL。注意CPU的類型。
2)、安裝SDK,前提是導出SDK的PB內核工程必須包括DirectShow或者其它組件。
29、在PB的config.bib文件中,“IMGFLASH”表示什么意思呢? 表示能夠刷NK到ROM中,具體請查看標題為“IMG Environment Variables”的幫助文檔。
30、x86平臺如何映射各種地址空間?如何編寫中斷服務例程? 如果是x86平臺,可以調用HalTranslateBusAddress轉換物理總線地址到物理系統地址,調用HalTranslateSystemAddress轉換物理系統地址到邏輯總線地址,也可以不調用這兩個函數,因為x86平臺除32位物理地址外還有16位的IO地址空間,對于16位的IO地址空間,可以直接調用WRITE_PORT_UCHAR或者READ_PORT_UCHAR等函數直接讀寫端口。對于32位物理地址可以調用VirtualAlloc和VirtualCopy來映射。這樣做思路清晰,簡單明了。
在x86平臺要實現ISR,有如下幾個步驟(以Geode BSP為例):
1)、用SETUP_INTERRUPT_MAP宏關聯SYSINTR和IRQ。以“SYSINTR_”為前綴的常量由內核使用,用于唯一標識發生中斷的硬件,又稱為中斷ID。在Nkintr.h文件中預定義了一些SYSINTR,OEM可以在Oalintr.h文件中自定義SYSINTR。
2)、用HookInterrupt函數關聯硬件中斷號和ISR。這里提到的硬件中斷號為物理中斷號,IRQ為邏輯中斷號。在InitPICs函數的最后調用了HookInterrupt函數,如下:
for (i = 64; i < 80; i++)
HookInterrupt(i, (void *)PeRPISR); ///用ISR關聯16個中斷號
3)、調用InterruptInitialize函數關聯SYSINTR和IST創建的事件對象,也是IST等待的事件對象。詳細內容請參考Geode BSP源碼。
在x86平臺要實現可安裝ISR,先調用LoadIntChainHandler函數注冊在注冊表中指定的ISR DLL,然后填充GIISR_INFO結構體并調用KernelLibIoControl函數將此結構體傳遞給可安裝ISR。詳細內容請參考WINCE幫助文檔或者我著的《Windows CE下驅動開發基礎》。
31、修改了WINCE自帶的驅動程序后如何編譯?如果是自己開發的驅動程序如何編譯?
1)、分為IDE方式和命令行方式。
IDE方式的編譯很簡單,以PB5.0為例,打開定制內核的工程,在左邊的“workspace”—“FileView”中找到你已經修改了的目錄,然后單擊右鍵彈出菜單,在菜單中選擇“Build and Sysgen Current Project”,這樣PB就會編譯指定的目錄中的項目源碼文件,然后執行sysgen命令根據source文件中的內容生成目標文件并復制到當前內核工程目錄下。
命令行方式的編譯需要打開“Build OS”—“Open Release Directory”,以cd命令進入你已經修改的驅動程序目錄中,然后鍵入“build –cfs”,然后鍵入“sysgen –p 項目名稱”,一般項目名稱為source文件中的“TARGETNAME”。
2)、如果想完全自己開發驅動程序,建議直接采用EVC或者PB來編寫編譯。
32、開發PCI設備驅動時,InterruptInitialize函數的第一參數是否是PCI卡配置空間信息中的InterruptLine 參數?是否需要在HKLM\Drivers\BuiltIn\PCI\Template 加一個自己的 subkey,并填寫相應內容?如何填? 1)、InterruptInitialize的第一參數是IRQ,也就是邏輯中斷號,而不是物理中斷號,InterruptLine是指物理中斷號
2)、需要在template下加自己的PCI設備的信息,例如:
[HKEY_LOCAL_MACHINE\Drivers\PCI\Template\Serial]
"Dll"="Com16550.Dll"
"Class"=dword:07
"SubClass"=dword:00
"ProgIF"=dword:02
"VendorID"=multi_sz:"0AF0","B320","B320"
"DeviceID"=multi_sz:"0020","0300","0302"
"Prefix"="COM"
而這些信息就來自于你執行pcienum.exe的結果。
33、編譯器報錯:error C2065: 'CFileFind' : undeclared identifier,如何解決? MFC for WINCE版本沒有CFileFind類,所以要查找文件只能調用API FindFirstFile 和FindNextFile。
34、如何設置WINCE系統字體、字號?如何設置自己開發的軟件的字體、字號? 1)、系統字體通過注冊表設置。如下:
[HKEY_LOCAL_MACHINE\System\GDI\SysFnt] ///系統字體
Wt=420
Ht=18
Nm=Arial
[HKEY_LOCAL_MACHINE\System\GWE\Menu\BarFnt] ///菜單欄字體
[HKEY_LOCAL_MACHINE\System\GWE\Menu\PopFnt] ///彈出窗口字體
[HKEY_LOCAL_MACHINE\System\GWE\Menu] ///菜單字體
HKEY_LOCAL_MACHINE\System\GWE\Button ///按鈕字體
2)、創建字體時把字體高度參數設置大點就可以了。如CFont::CreateFont(nHeight,...),也可以在LOGFONT結構中設置字體高度或者字體種類。如果是控件,調用控件的SetFont成員函數。如果是直接畫,在OnPaint響應函數中調用SelectObject選字體到DC。
35、 nk.bin和nk.nb0有什么區別? 這里提到的bin是一種二進制鏡像格式,以片斷(section)為單位組織數據,每個片斷都包括一個頭,頭里指定了起始地址,長度,校驗值。Platform Builder調用工具將WINCE內核所有文件以bin格式合并成一個文件,默認文件名為nk.bin。BootLoader又以同樣的格式將nk.bin分解成多個文件放到RAM中。可以在命令行中鍵入“viewbin nk.bin”來查看bin文件中具體包括了哪些內容。鍵入Cvrtbin命令轉換.bin格式文件為.sre格式或者.abx格式。
nb0格式是原始的二進制鏡像,它不包括頭,一般情況下將內核下載到設備的RAM中運行都采用nb0格式。要生成nbx格式的文件,需要在相關.bib文件中確定如下值:ROMSTART、ROMWIDTH、ROMSIZE。
36、在不采用硬件計時器的情況下如何創建更精確的計時器?最精確周期能否達到1毫秒?
對于精確值的要求不同,所采用的辦法不同。以下闡述幾種辦法。
1)、在單線程中循環調用API Sleep函數,Sleep函數精確程度為如果Sleep(N),那么實際睡眠時間在N到N+1毫秒之間。而且還要注意調用Sleep的線程優先級的問題。如果任務過多并且此線程優先級低,那誤差就更大些。
2)、調用API QueryPerformanceCounter函數,舉例如下:
LARGE_INTEGER liFrequency;
if (QueryPerformanceFrequency(&liFrequency)) // 查詢系統時鐘的頻率,這里將返回1000
{
liFrequency.QuadPart /= 1000;
LARGE_INTEGER liTimeOut;
if (QueryPerformanceCounter(&liTimeOut)) //得到截至到當前累計發生的系統時鐘中斷次數
{
liTimeOut.QuadPart += liFrequency.QuadPart; ///計算下一秒到來時總的中斷次數是多少
LARGE_INTEGER liCurrent;
do
{
QueryPerformanceCounter(&liCurrent); // 循環查詢累計的的中斷次數
} while (liCurrent.QuadPart < liTimeOut.QuadPart); ///到達下一秒
}
}
調用QueryPerformanceCounter同調用Sleep在本質上都是一樣的,都是在單線程中無限循環等到周期一到執行任務,相比較QueryPerformanceCounter要比Sleep更精確些,越精確就越要求線程的優先級,保障線程能夠正常得到處理器。
3)、以上辦法難以保證周期精確到1毫秒并且WINCE系統穩定地運行,所以要從中斷入手。以x86平臺為例,先在Timer.c中將默認的SetTimer0(TIMER_COUNT)中的TIMER_COUNT /=2,SetTimer0函數負責設置系統時鐘的頻率,默認1毫秒發生一次中斷,如果除以2就是0.5毫秒發生一次中斷。然后在fwpc.c文件中修改ISR函數PeRPISR,因為原來默認是1毫秒發生一次中斷,在處理INTR_TIMER0時系統負責累計計數、管理線程的調度,返回相應的SYSINTR值,而我們沒有辦法再添加代碼返回自己定義的SYSINTR值,所以現在要修改原來的處理代碼,例如設置一個BOOL型變量,TRUE就執行原來默認的代碼,而FALSE就返回我們自己定義的SYSINTR值,這樣即不影響原來的ISR處理,又加入了我們的中斷響應代碼。ISR返回我們定義的SYSINTR后WINCE內核激活相對應的EVENT事件,我們就可以在我們編寫的IST里處理任務了。
37、flash中存放了BootLoader和內核鏡像,如何把剩余flash部分劃分為一個存儲區域供應用程序讀寫?
以WINCE提供的驅動(FAT文件系統和MSFLASH驅動)來舉例說明。如果采用默認common.reg中的注冊表設置,那么MSFLASH驅動默認把整個flash作為存儲區域來讀寫,這不符合問題的要求,所以必須告訴MSFLASH驅動程序可供讀寫的區域的起始地址和長度。以下是一個注冊表例子:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\FASLD]
"Dll"="fasld.dll" ///實際Flash存儲器的驅動程序
"Order"=dword:2 ///該驅動程序相對于其它驅動程序的加載順序
"Prefix"="DSK" ///前綴
"Ioctl"=dword:4 ///IOCTL碼,設備管理器加載驅動的時候調用IOControl函數,傳遞這個IOCTL碼。
"Profile"="MSFlash" ///Profile名稱,也就是[HLM\System\StorageManager\Profiles\MSFlash]
///當設備管理器加載此驅動程序的同時發送通知給系統,IClass(GUID)的值表明這是一個存儲設備的驅動程序。
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"MemBase"=dword:00000000 ///Flash中可供讀寫區域的起始物理地址,也就是Flash的首地址+偏移量
"MemLen"=dword:00000000 ///Flash中可供讀寫區域的長度
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\MSFlash]
"DefaultFileSystem"="FATFS" ///MSFlash驅動默認采用的文件系統
"PartitionDriver"="mspart.dll" ///采用的分區驅動程序
"MountAsRoot"=dword:1 ///此目錄作為文件系統的根目錄
"Folder"="NOR Flash" ///目錄名稱
"Name"="FLASH Disk Block Device" ///Flash驅動名稱
"PartitionDriverName"="MSPART" ///分區驅動名稱
"AutoMount"=dword:1 ///自動裝載檢測到的分區
"AutoPart"=dword:1 ///自動分區
"AutoFormat"=dword:1 ///自動格式化分區
[HKEY_LOCAL_MACHINE\System\StorageManager\AutoLoad\MSFlash]
"DriverPath"="Drivers\\BuiltIn\\FASLD" ///Flash驅動在注冊表中的位置
"LoadFlags"=dword:1 ///這個值可以被設置為0、1、2。1表示同步加載,其它表示異步加載
"Order"=dword:0
[HKEY_LOCAL_MACHINE\System\StorageManager\FATFS]
"FriendlyName"="FAT FileSystem" ///文件系統名稱
"Dll"="fatfsd.dll" ///文件系統驅動程序
"Flags"=dword:00000064 ///標志,詳見幫助文檔
"Paging"=dword:1 ///是否分頁
"EnableCache"=dword:1 ///是否允許緩存數據
"CacheSize"=dword:0 ///指定緩存大小,0表示默認
38、驅動程序如何發通知給應用程序? 這里介紹一下常見的兩種辦法。
1)、驅動程序調用API SendNotifyMessage,發送特定的消息給應用程序,這就要求應用程序要有消息循環機制并且要事先做好消息的處理。參數1為窗口句柄,可以設置HWND_BROADCAST表示廣播消息。要注意的是不要在參數中傳遞指針(虛擬地址),因為執行驅動程序的線程和應用程序并不在同一個進程空間中。解決辦法可以利用內存映射文件技術,比如在驅動程序中創建一個內存映射文件對象,申請一塊物理內存,然后把對象名稱和內存長度傳遞給應用程序,應用程序打開同名的內存映射文件對象,讀取里面的數據。對象名稱可以事先協定好,也可以通過注冊表來傳遞,內存長度是32位值,通過消息參數就可以傳遞,也可以通過注冊表來傳遞。另外一種解決辦法是在定制內核時候預留一塊物理內存,這樣驅動程序和應用程序都可以通過VirtualAlloc和VirtualCopy來映射到同一塊物理內存,其原理同內存映射文件技術一樣,但是這塊物理內存不具備通用性。最后一個辦法是應用程序事先將一個緩沖區地址傳遞給驅動程序,驅動程序調用MapPtrToProcess映射應用程序傳遞過來的地址,當驅動程序調用SendNotifyMessage后應用程序可以直接到該地址中讀取數據。
設備管理器就是調用此函數廣播WM_DEVICECHANGE消息的。另外WINCE的一個例子程序RNAApp在撥號連接建立的時候也是調用這個函數廣播WM_NETCONNECT消息的。
2)、驅動程序調用API CeEventHasOccurred指明一個事件A發生,在此之前應用程序調用API CeRunAppAtEvent將驅動程序指明的A事件和一個應用程序名稱相關聯,或者和一個事件B相關聯。這樣當A事件發生時,如果指明和一個應用程序名稱關聯,那這個應用程序就會被啟動。如果指明了和一個事件B相關聯,那么等待事件B的線程將被激活。如果想了解當前系統內部所有驅動程序支持哪些類似事件A的事件,調用API CeNotifyPublic_FilterEvent,在該API的幫助文檔里也列舉了常見的事件,例如NOTIFICATION_EVENT_NET_CONNECT和 NOTIFICATION_EVENT_NET_DISCONNECT。
40、 EVC創建的工程名稱如果用中文就出錯,該怎么辦? 用EVC創建的工程名稱如果為中文將導致資源文件打不開和編譯出錯,可以改資源文件名稱為英文,再編輯.rc文件中的資源文件名稱。但建議盡量不要用中文為工程名稱。
作為習慣,應該在EVC創建一個工程后,立刻在“project”—“settings”中設置資源的語言屬性,然后在“resource view”中設置每個資源的語言屬性,這些工作做完后再修改資源就沒有問題了。有人詢問對話框的標題為亂碼,其原因就是在沒有修改語言屬性的情況下設置標題為中文。
posted on 2009-07-16 15:41
Sandy 閱讀(741)
評論(0) 編輯 收藏 引用 所屬分類:
Windows Mobile