EVC一些常用的技巧

1.怎樣在一個控件獲得焦點時打開軟鍵盤?
比如一個EditBox獲得焦點後,這個時候自動打開軟鍵盤,這樣可以方便用戶輸入——SIPINFO、SHSIPINFO、SIPSETINFO、SIPGETINFO裏面有些參數弄不明白
//隱藏輸入面板
BOOL LowerSip()
{
BOOL fRes = FALSE;
SIPINFO si;
memset( &si, 0, sizeof( si ) );
si.cbSize = sizeof( si );
if( SHSipInfo( SPI_GETSIPINFO, 0, &si, 0 ) )
{
si.fdwFlags &= ~SIPF_ON;
fRes = SHSipInfo( SPI_SETSIPINFO, 0, &si, 0 );
}
return fRes;
}

//升起輸入面板
BOOL RaiseSip( void )
{
BOOL fRes = FALSE;
SIPINFO si;
memset( &si, 0, sizeof( si ) );
si.cbSize = sizeof( si );
if( SHSipInfo( SPI_GETSIPINFO, 0, &si, 0 ) )
{
si.fdwFlags |= SIPF_ON;
fRes = SHSipInfo( SPI_SETSIPINFO, 0, &si, 0 );
}
return fRes;
}
再試試下面這些:
//SHSipPreference(m_hWnd, SIP_UP);//彈出輸入面板
//SHSipPreference(m_hWnd, SIP_DOWN);//隱藏輸入面板(有一個時延)
//SHSipPreference(m_hWnd, SIP_FORCEDOWN );//隱藏輸入面板(立即)
//SHSipPreference(m_hWnd, SIP_UNCHANGED );
//一般只用在調用SIP_DOWN時的的後面,使這個命令無效

--------------------------------------------------------------------------------
2.WinCE下字符串-數字轉化的問題!
在VC6.0下,把#i nclude <stdlib.h>、#i nclude <stdio.h>兩個文件包括進去後,下面這段代碼一點問題沒有,
CString str1,str2;
str1="123";
str2="123.4";
int i;
float j;
i=atoi(str1);
j=atof(str2);
但是在EVC3.0裏面,卻出現了問題:提示atof沒有定義,atoi也不能正常轉化。

用wcstoi,wcstof, wcstol和wcstod
--------------------------------------------------------------------------------
3. 我新拿了一個Pocket Pc,編了幾個程序,但發現對話框都只能全屏顯示,這是爲什麼?
一般在Pocket PC中所有的對話框都是全屏顯示,這是操作系統規定的行爲。但如使用系統自定義的信息提示框,則不是全屏顯示。如: Afxmessagebox所激發的提示框就是如此。
可以重載WM_INITDIALOG消息
MSDN:
The DialogBox macro uses the CreateWindowEx function to create the dialog box. DialogBox then sends a WM_INITDIALOG message to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

就是說當對話框窗口創建完以後,會發出一個WM_INITDIALOG 消息,你只要在自己的窗口消息處理函數裏對這個消息進行處理,就可以了
比如:

case WM_INITDIALOG:
// Create a Done button and size it.
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
InitOptionDlg(hDlg);
return TRUE;

主要就是修改shidi.dwFlags ,看看ABOUT的窗口消息處理吧
補充: SHINITDLGINFO shidi;
SHINITDLGINFO shidi;
上面說的是在純API的程序中的方法
對於MFC創建的DIALOG程序,可以這樣:

BOOL CXXXDlg::OnInitDialog()
{

SHINITDLGINFO shidi;
HWND hDlg = m_hWnd;
// Create a Done button and size it.
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_SIPDOWN ;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
//InitOptionDlg(hDlg);
//CDialog::OnInitDialog();
……

}
--------------------------------------------------------------------------------
4.在eVC基於MFC的程序中如何將ToolBar欄隱藏
關於ToolBar的隱藏:
首先,如果你是用MFC嚮導創建的工程,則默認會生成ToolBar,我要說的是,幹掉它!自己來創建。:)
First,聲明CToolBar成員變量:
CToolBar * d_pToolbar2;
然後……
static UINT BASED_CODE Toolbar2Buttons[] =
{
// 下面是工具欄對應菜單的ID,工具欄圖標是我弄的一個Bitmap,其ID爲IDR_ADD_TOOLBAR
ID_FILE_NEW,
ID_FILE_OPEN,
ID_FILE_SAVE,
ID_SEPARATOR,
ID_EDIT_CUT,
ID_EDIT_COPY,
ID_EDIT_PASTE,
ID_SEPARATOR,
ID_TRANS_DICT,
ID_TOOLBAR_SHOW, //這是新加入的菜單項,點擊隱藏工具欄,再點擊就顯示工具欄
};
然後……
在CMainFrame的OnCreate()中加入:
OnToolbarCreate();
然後……
void CMainFrame::OnToolbarCreate()
{
// Should only get here if we don/'t have a toolbar.
ASSERT(d_pToolbar2 == 0);
// Create C++ object and WinAPI window.
d_pToolbar2 = new CToolBar();
d_pToolbar2->Create(this, WS_CHILD | CBRS_BOTTOM |
CBRS_SIZE_FIXED | CBRS_FLOATING,
0x9100);
// Get bitmap and connect to tool items.
d_pToolbar2->LoadBitmap(IDR_ADD_TOOLBAR);
d_pToolbar2->SetButtons(Toolbar2Buttons,
sizeof(Toolbar2Buttons)/sizeof(UINT));
// Make toolbar dockable.
d_pToolbar2->EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(d_pToolbar2);
}
然後……
void CMainFrame::OnToolbarShow()
{
ASSERT(d_pToolbar2 != 0);

// Query current visibility.
BOOL bVisible = (d_pToolbar2->GetStyle() & WS_VISIBLE);

// Show or hide.
int nShow = (bVisible) ? SW_HIDE : SW_SHOWNORMAL;
d_pToolbar2->ShowWindow(nShow);

// Reconfigure remaining toolbar items.
RecalcLayout();

// Store visibility state for later.
d_bToolbarVisible = (!bVisible);
}

void CMainFrame::OnUpdateToolbarShow(CCmdUI* pCmdUI)
{
//This function is signed for checking the menu /'Edit|Show Toolbar/'
pCmdUI->Enable(d_pToolbar2 != 0);
int nCheck = (d_bToolbarVisible) ? 1 : 0;
pCmdUI->SetCheck(nCheck);
}

OK,默認情況下ToolBar是隱藏的,點擊菜單中的新加入的隱藏/顯示工具欄命令即可來回切換了。
--------------------------------------------------------------------------------
5.如何製作pocket Pc 下的安裝程序?
在C://Windows CE Tools//wce300//MS Pocket PC//support//ActiveSync//windows ce application installation 下面有例子.
也有其它第三方的安裝工具,比如installshield。

--------------------------------------------------------------------------------
6.怎樣在主界面中顯示一幅圖片
我做了一個小程序, 想在主界面中顯示一幅圖片,我的圖片是.JPG格式的,如果需要轉換,用什麼工具?
把JPG圖轉爲BMP圖咯,網上有不少這樣的程序。
然後用LoadBitmap、SelectObject、StretchBlt等語句把BMP圖顯示到VIEW中。


--------------------------------------------------------------------------------
7. 請問,在WinCE下如何截獲所有鼠標和鍵盤的消息?
wince下只能用三種鉤子
#define WH_JOURNALRECORD 0
#define WH_JOURNALPLAYBACK 1
#define WH_KEYBOARD_LL 20

--------------------------------------------------------------------------------
8.在Pocket PC下用eVC作的對話框能否做成不是全屏的?
在MFC中
m_bFullScreen = FALSE;

--------------------------------------------------------------------------------
9.如何將char 類型的中文字符串轉換成Unicode的字符串?
MultiByteToWideChar,在仿真器中無效;你也可以通過其他方法;用wcsprintf這個函數

--------------------------------------------------------------------------------
10. evc單文檔界面中,菜單左邊總有一個"new",如何將其去掉?
在MainFrm的OnCreate內找到這個:
m_wndCommandBar.m_bShowSharedNewButton = TRUE;
把TRUE改爲FALSE

--------------------------------------------------------------------------------
11.Edit出現上下文菜單問題?
近 來我看了一下SDK帶的Sample中的Npp,其中它有一個功能就是在EDIT上出現上下文菜單,可是當我仿照它在自己的項目中添加此功能時,即在資源 中添加CONTROL "",IDC_STATIC,"SIPPREF",NOT WS_VISIBLE,-10,-10、,6,6,在模擬器中正常,但在PDA中不能顯示包含Edit的對話框。而Npp可以在兩者正常顯示。我又在 Npp中增加一個對話框,也相應的改變資源,結果是在模擬器和PDA中都能正常顯示。
調用SHInitExtraControls()應該在構造函數,不應在OnInitDialog中。如果在OnInitDialog中調用,包含EDIT的對話框將不顯示。
事實上在XXXApp::InitInstance函數中調用更好,這樣只需調用一次,就萬事大吉。

--------------------------------------------------------------------------------
12. 如何將.mdb數據庫轉換爲.cdb數據庫
如何將.mdb數據庫轉換爲.cdb數據庫,在沒有實際PDA,只有Pocket PC Emuliation和EVB的情況下。
Pocket PC Emuliation運行時爲何提示“存儲器不足,無法完成操作”?

此問題微軟已經給出了答案。
在SDK文檔中有一個叫做device的例子程序,它就是將tdb文件轉化成cdb文件的,而還有一個desktop的程序,它是將mdb文件轉化成tdb文件的。


--------------------------------------------------------------------------------
13.請問如何用EVC建立和調用DLL
我按照幫助中用MFC開發DLL的例子做,但是另外一個程序調用的時候的時候卻出現連接錯誤,說找不到那個函數。後來看了EVC的例子spintest之後也是這樣。
和在WINDOWS下的一樣
是不是LINK2001 ERROR?
你如果是隱式調用(就是不用LOADLIBRARY()的),要把你的DLL的LIB文件在PROJECT-->SETTINGS--->LINK--->INPUT裏指明。

--------------------------------------------------------------------------------
14.編輯框如何自動會換行 ?
請教,Plam中的table控件,在Wince上怎麼做?
就是編輯框自動會換行.當你輸入的內容超過一行,自動切換到下一行,下面的內容自動往下滾。

勾選編輯控件的MultiLine,如果想輸入回車換行,再勾選want renturn
--------------------------------------------------------------------------------
15.是否在adoce,pocket access中的update語句不能執行?
ADOCE不能直接執行UPDATE語句,但ADOCE有Update方法,你可用它實現。

--------------------------------------------------------------------------------
16.請問如何在Windows CE中實現BC++中的inport(...)與outportb(...)函數功能?
CE下,可以用WINDOWS API函數來對端口操作。 比較簡單。
API一般只要用到CreateFile(打開端口,串口操作和文件操作只有一點不同就是打開方式不同,所以第三個參數要用 OPEN_EXISTING )
COMMTIMEOUTS、DCB兩個結構是存放設置參數的,可以改
WriteFile、WriteFile(讀寫端口)
因爲串口通訊用的是異步通訊,所以下面兩句比較重要
SetCommMask(指定監視的端口事件)
WaitCommEvent(等待端口事件)

--------------------------------------------------------------------------------
17. 如何顯示一個對話框讓用戶選擇一個目錄而不是文件
沒有標準的函數處理這個,你只好自己實現活使用第三方的解決方案。

--------------------------------------------------------------------------------
18.有沒有辦法(API)激活或禁止電源保存模式?
參看SystemIdleTimerReset()的安裝文檔。創建一個包含象睡眠的無限循環的線程,然後調用SystemIdleTimerReset()。也許有一種中斷線程的辦法就是程序退出。

--------------------------------------------------------------------------------
19. Windows CE的文件名最小程度是多少?
在windef.h定義了MAX_PATH,普遍應該是260個字符。
20. 我使用CFileDialog創建了一個瀏覽按鈕,默認目錄始終是顯示"All Folders"和在"//My Device//My do***ents"下。怎樣改變初始目錄到"//My Device"。使用fileDlg.m_ofn.lpstrInitialDir = TEXT(" file://My/ Device");,但是沒有改變默認顯示的目錄。
lpstrInitialDir指向一個指定初始文件目錄的字符串。如果爲NULL,將使用系統的根目錄。儘量嘗試一下lpstrInitialDir爲NULL。


--------------------------------------------------------------------------------
21.在Pocket PC任務欄上可能有X和OK按鈕嗎?
不可能,至少沒有象WisBar的第三方工具。


--  作者:admin
--  發佈時間:2008-12-25 13:41:56
--  
--------------------------------------------------------------------------------
22.如何禁止用戶改變日期和時間?有可能實現嗎?
你可能用自己的程序替代//windows//clock.exe,但是,它們可以通過另外的程序處理這個。同樣,在同步時ActiveSync改變設備的時間與PC匹配。

--------------------------------------------------------------------------------
23.  我有一個xscal cpu的ipaq 3970設備,但是在eMbedded Visual C++ 3.0上沒有目標類型。我應該在EVC3.0上使用什麼類型。這個問題也發生在安裝程序Cabwiz.exe上。
你可以使用ARM類型。XScal基於ARM體系。

--------------------------------------------------------------------------------
24.  如何使程序在後臺運行?
最小化程序將使程序進入後臺,因此只要在程序啓動時最小化,那麼它將運行在後臺。
補充:還可以做成service。
--------------------------------------------------------------------------------

25.  我準備去掉SIP按鈕。我在OnInitDialog事件中使用SHFullScreen。然而SIP按鈕仍然可見,忘記做什麼了嗎?
代碼如下:
// SHFullScreen fails if dialog box is not foreground.
SetForegroundWindow();
// Go to the full screen mode
SHFullScreen(m_hWnd, SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);


不能在OnInitDialog中使用SHFullScreen,因爲對話框還沒有可見。你應該傳遞一個自定義消息,在那個消息調用這個函數。
也許下面這段代碼會有用:
void PFCSipButtonShow( BOOL bShow )
{
HWND hWnd = ::FindWindow( _T( "MS_SIPBUTTON" ), NULL );
if (hWnd == NULL)
return;

if (bShow)
::ShowWindow( hWnd, SW_SHOW );
else
::ShowWindow( hWnd, SW_HIDE );

} // PFCSipButtonShow

--------------------------------------------------------------------------------
26. 如何在Pocket PC2002模擬器上安裝Pocket PC程序?
PPC2002 模擬器沒有模擬ARM處理器,因此你必須有x86 CPU的二進制文件和相應的安裝程序。只需使用文件瀏覽器複製cab文件到模擬器,然後執行它。商業程序的安裝包通常不包含x86的二進制程序。如果你沒 有x86處理器的程序發佈版本,你不能做這個安裝。如果程序是你自己的,你可以創建一個x86的版本,之後創建一個安裝CAB。

--------------------------------------------------------------------------------
27.  如何在eVC程序中讀取普通的圖標文件?
在PC程序中使用ExtractIconEx(),但是在Pocket 設備好象不工作。缺少了什麼?PC圖標文件在Pocket PC環境是非法的?或者需要轉換格式?
不幸的是,在Pocket PC上沒有API去讀取圖標。因此,你不得不手工解析圖標文件。
--------------------------------------------------------------------------------
28. 如何繪製一個透明的圓呢?
我想使用eVC++和GDI在Pocket PC 2002上繪製一個圓。我使用它繪製了直線,它處理的很好:
hbrOld =(HBRUSH) SelectObject(hDC, CreatePatternBrush(RGB(0,255,0)));
hpnOld =(HPEN) SelectObject(hDC, CreatePen(PS_SOLID, 2, RGB(255,0,0)));
Ellipse( hDC, 10, 10, 20, 20);
DeleteObject( SelectObject (hDC, hbrOld) );
DeleteObject( SelectObject (hDC, hpnOld) );

但是如何繪製一個透明的圓呢?有PS_NULL這樣畫筆類型嗎?
可以使用GetStockObject()得到一個NULL_BRUSH或HOLLOW_BRUSH(這兩個是相同的)。然後用SelectObject選擇它,就象你已經做的那樣。
--------------------------------------------------------------------------------
29.  假定我知道程序的名稱,關閉運行着的eVC的程序使用什麼API?
如果你知道程序的名稱,並且假定與主窗口的名稱相同,那麼你可以使用FindWindow得到那個窗口的句柄,然後傳送WM_CLOSE消息到那個窗口。
HWND hwnd = FindWindow(NULL, _T("APPLICATION NAME"));
if ( hwnd)
PostMessage(hwnd, WM_DESTROY, 0, 0);


--------------------------------------------------------------------------------
30.  如何從PC設置PDA的時間?
最簡單的辦法是寫一個自定義的RAPI函數,通過CeRapi調用設備的SetSystemTime.

--------------------------------------------------------------------------------
31.  怎樣使用WriteBinary,我不明白第二個參數(LPBYTE):
BOOL CVORegistry::WriteBinary(LPCTSTR pcszKey, LPBYTE pData, DWORD cbData)
第二個參數是指向包含你想寫到註冊表的二進制數據的緩衝。
BYTE data[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef };
extern CVORegistry reg;
reg.WriteData(_T("BinaryData"), data, sizeof(data));

--------------------------------------------------------------------------------
32.  Windows CE支持鉤子API嗎?這樣我們可以監視需要的時間。如果支持,用法也象Windows 2000那樣嗎?
壞消息:CE不支持鉤子。
系統不支持,我們還是可以想其他辦法的……圖片點擊可在新窗口打開查看

--------------------------------------------------------------------------------

33.  我不能使用Pocket PC上CDialog的TitleBar,我能用靜態文本框控件替代,使之與TitleBar相似。有辦法顯示TitleBar嗎?
大多數Pocket PC上的對話框是全屏的,沒有自己的主題欄,而是使用系統任務欄。你可以創建一個非全屏對話框(象消息框那樣)。

--------------------------------------------------------------------------------
34.  如何在程序中關閉(suspend)Pocekt PC?
方法1:虛擬關機鍵
::keybd_event(VK_OFF, 0, 0, 0);
::keybd_event(VK_OFF, 0, KEYEVENTF_KEYUP, 0);

方法2:調用未公開函數PowerOffSystem()
extern "C" __declspec(dllimport) void PowerOffSystem();


--------------------------------------------------------------------------------
35.  如何在程序中重啓(soft reset)Pocket PC?
#i nclude
#define IOCTL_HAL_REBOOT CTL_CODE(FILE_DEVICE_HAL, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
extern "C" __declspec(dllimport) BOOL KernelIoControl(
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned);
BOOL ResetPocketPC()
{
return KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
}


--------------------------------------------------------------------------------
36. 如何在程序中硬啓動(hardware reset)Pocekt PC?
注意:使用此段代碼會將您的Pocket PC的用戶數據全部清空。
#i nclude
#define IOCTL_HAL_REBOOT CTL_CODE(FILE_DEVICE_HAL, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
extern "C" __declspec(dllimport)void SetCleanRebootFlag(void);
extern "C" __declspec(dllimport) BOOL KernelIoControl(
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned);
BOOL HardResetPocketPC()
{
SetCleanRebootFlag();
return KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
}


--------------------------------------------------------------------------------
37.  以下方法信息不全,無法使用:
1.系統不認識VK_OFF
2.使用哪個dll 和 lib文件?


·  如何在程序中關閉(suspend)Pocekt PC?
方法1:虛擬關機鍵
::keybd_event(VK_OFF, 0, 0, 0);
::keybd_event(VK_OFF, 0, KEYEVENTF_KEYUP, 0);

方法2:調用未公開函數PowerOffSystem()
extern //"C//" __declspec(dllimport) void PowerOffSystem();

關閉(suspend)
方法1:
//虛擬關機鍵
::keybd_event(VK_OFF, 0, 0, 0);
::keybd_event(VK_OFF, 0, KEYEVENTF_KEYUP, 0);

方法2:
//調用未公開函數PowerOffSystem()
extern "C" __declspec(dllimport) void PowerOffSystem();

--  作者:admin
--  發佈時間:2008-12-25 14:25:14
--  

 

思維習慣埋下的陷阱:在eVC中使用Slider、Spin等控件

 

前幾天,我定下了使用GWES的UI 方案,週一開始工作後,果然在兩天內應用程序開發一路高歌猛進勢如破竹,大家用DialogBox、Button、Static Text控件都覺得巨爽無比,總比自己從CreateWindowEx開始寫,然後一步一步CODE REVIEW和TEST上來舒服多了。但是昨天傍晚的時候,工程師A遇到個問題,在對話框中加入Slider(進度條)後,該DialogBox就無法顯 示出來了。

工程師A鬱悶了一早上,把 DialogBox和Slider的屬性翻來覆去地改,最後索性對.rc文件直接作文本編輯,但仍然沒有效果。下午工程師B也放下手裏的活,協助解決這個 問題,仍然沒有結果。問題的答案結果實在簡單到無語,是工程師A沒有仔細看文檔導致的,然後工程師B也順着A的方向落入思維陷阱,我也前赴後繼掉進去了, 一共折騰了大概15人時才爬出來。

晚飯後,我解決的思路大致如下

1、懷疑是DlgProc在 WM_INITDIALOG或WM_PAINT時的處理不善導致。所以索性在DlgProc的首行直接打印消息看是否得到的消息正確。結果:只依次得到三 個消息WM_SETFONT、WM_WINDOWPOSCHANGED、WM_CLICKACTIVE。連WM_INITDIALOG都沒有收到。本思路 否決。

2、懷疑是控件的STYLE問題,這 個思路是沿着工程師A的方向考慮的。我嘗試用VC6建立了X86上的PROEJCT,在VC6裏建立DIALOG和SILDER,發現運行起來顯示正常。 於是比較了VC6的這個RC文件和EVC裏有問題的RC文件,發現WINCE支持的控件STYLE只是WINXP上的一個子集。

3、繼續上一步思路,在WINCE500裏找到其他帶有SILDER的RC文件,找到了控制面板裏的Volume音量控制。拿來和出問題無法顯示的RC做文本比較,發現兩份RC文件沒有差異,我這份的結果仍然出不來。思路2、3否決。

4、所以是代碼問題。嘗試了DialogBox和CreateBox, 結果一樣出不來。

5、由於昨天在WINCE模擬器上遇到的一個靜態全局變量地址傳遞異樣的問題,所以我懷疑這是模擬器導致。把塵封已久的開發板連接起來跑,發現問題仍然存在。

6、想到TCPMP和音量控制即使跑模擬器上也仍然正常顯示Slider控件,於是徹底推翻第5條假設。

7、考慮是否爲STANDARDSDK_500和IBMCE兩個PROJECT都缺少某個支持SLIDER所需的組件導致。由於前面第6條判斷,於是立刻推翻本條推理

8、目前排除RC的問題,定位爲代碼或系統原因。我在WINCE HELP裏搜了一下關鍵字“slider”,搜索結果第一條就是"Createing a TrackBar", 和目錄同步後,發現該頁處於目錄結構
Shell and User Interface -> Shell -> Shell Application Development -> Create Controls
而不是描述BUTTON控件的
Shell and User Interface -> Graphics, Windowing and Events -> GWES Reference -> Window Control Reference
看到這裏就知道方向應該對了。前面我們都習慣性思維認爲所有的控件都在GWES下面,所以調用方式都一樣的,而實際上雖然同樣有着CONTROL的名頭,卻分在不同目錄下,其中必有文章。

9、仔細看看Create Controls那一頁,開頭列出了多種控件的名字,但是沒有BUTTON和STATIC TEXT。我選擇了表格裏的Tree views和Date and time picker控件,在EVC裏把這兩種控件分別加入DIALOG,結果DIALOG同樣也顯示不出來。這就進一步肯定了思考方向已經正確。

10、就ms-help://MS.WindowsCE.500/wceshellui5/html/wce50conworkingwithcommoncontrols.htm 這頁看到下面,有這個描述

Before you create or use any common controls, you must register them. You register a common control by calling the InitCommonControlsEx function, which registers a specific set of common control classes. Calling InitCommonControlsEx ensures that the common DLL is loaded.

To use most of the common controls, you must include the Commctrl.h header file in your application. To use property sheets, you must include the Prsht.h header file.

MS還特意加粗了 InitCommonControlEx。那麼估計就是在工程師A的代碼裏面,沒有調用該函數把COMMON CONTROL這個DLL加載進來。我查了一下InitCommonControlEx,先填寫一個結構體參數就OK了。後來試了下,不填寫結構體,直接 調InitCommonControl()也是可以的。OK,都顯示出來了,Tree View和Date and time picker也都可以顯示了。

————————————————

總 結起來,這事的思維陷阱在於:認爲eVC繪圖面板上的所有控件,調用方式都一樣。因爲VC上的繪圖面板上控件調用方式都一樣,而且即使eVC裏其他以面板 來分類的功能和操作,比如調試面板、文件操作面板,同個面板上按鈕使用方法也幾乎一樣。這和我前面因爲點了繪圖控件就想着立刻去點Class Wizzard關聯MFC類,因此在項目早期評估時錯過GWES實現方案的邏輯漏洞有相似之處。結果就是,表面上看起來同類的、十分相似的東西,它的用法 卻可能是不同的。對接口函數或者工具的使用,還是必須忠於文檔,而不是直覺。


--  作者:admin
--  發佈時間:2008-12-25 14:46:56
--  

EVC開發技巧

 

//Hard Reset!

#include <winioctl.h>

#define IOCTL_HAL_REBOOT CTL_CODE(FILE_DEVICE_HAL, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)

extern "C" __declspec(dllimport)void SetCleanRebootFlag(void);

extern "C" __declspec(dllimport) BOOL KernelIoControl(
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned);

BOOL HardResetPocketPC()
{
SetCleanRebootFlag();
return KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
}

////////////////////////////////////////////////////

//全屏
void FullScreen(HWND hDlg)
{
RECT rc;
GetWindowRect(hDlg, &rc);  
SHFullScreen(hDlg, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);
MoveWindow( hDlg, rc.left, rc.top, rc.right,  rc.bottom, TRUE);  
}

//類似參數要注意SHFS_HIDETASKBAR HIDE爲隱藏、SHOW爲顯示

////////////////////////////////////////////////////


//WinSDK編程 顯示隱藏光標

int  nWaitCursorCount; //光標記數器

/******************************************************
*顯示隱藏光標nCode=1爲顯示,-1爲隱藏
*****************************************************/
void SHCursor(int nCode)
{
    static HCURSOR cur;
    static BOOL bo=true;
if (bo)
{
  cur = ::LoadCursor(NULL, IDC_WAIT);
  bo = false;
}
m_nWaitCursorCount += nCode;
if (m_nWaitCursorCount > 0)
{
  HCURSOR hcurPrev = ::SetCursor(cur);
  if (nCode > 0 && m_nWaitCursorCount == 1)
   m_hcurWaitCursorRestore = hcurPrev;
}
else
{
  // turn everything off
  m_nWaitCursorCount = 0;     // prevent underflow
  ::SetCursor(m_hcurWaitCursorRestore);
}
}

/******************************************************
*開始顯示光標
*****************************************************/
void BeginCursor()
{
m_nWaitCursorCount = 0;
SHCursor(1);
}

/******************************************************
*結束顯示光標
*****************************************************/
void EndCursor()
{
m_nWaitCursorCount = 0;
SHCursor(-1);
}

//////////////////////////////////////////////////////////

//調用其它程序

/******************************************************
*打開其它應用程序
*****************************************************/
void Shell(HWND hWnd,LPTSTR ProPath)
{
int ret;
    LPTSTR exec = (LPTSTR)malloc(MAX_PATH);
    SHELLEXECUTEINFO shi;
    exec = ProPath;
    shi.cbSize = sizeof(SHELLEXECUTEINFO);
    shi.lpVerb = TEXT("open");
    shi.lpFile = exec;
    shi.nShow = SW_SHOWNORMAL;
    ret = ShellExecuteEx(&shi);
}

////////////////////////////////////////////////////////

//WINSDK 彈出式菜單

/******************************************************
*彈出菜單
*****************************************************/
VOID APIENTRY PopupMenu ( HWND hWnd, POINT point, int IDM)
{
  HMENU hMenu;
  HMENU hMenuTrackPopup;
  
  // 得到彈出菜單資源
  hMenu = LoadMenu (ghInst, MAKEINTRESOURCE(IDM));
  if (!hMenu)
    return;

  hMenuTrackPopup = GetSubMenu (hMenu, 0);  
  ClientToScreen (hWnd, (LPPOINT)&point);  
  TrackPopupMenu (hMenuTrackPopup, 0, point.x, point.y, 0, hWnd, NULL);
  DestroyMenu (hMenu);
}


--  作者:admin
--  發佈時間:2009-3-6 14:28:21
--  
  在應用程序中,如何向修改本機的ip 地址等網絡參數,並使之立即生效?  
網絡設置保存在註冊表中,位置[HKEY_LOCAL_MACHINE//Comm//網卡名稱//Parms//TcpIp],例如常見的CS8900網卡設置:  
[HKEY_LOCAL_MACHINE//Comm//CS89001//Parms//TcpIp]  
   "EnableDHCP"=dword:0  
   "DefaultGateway"="192.168.0.1"  
   "DNS"="111.111.111.111"  
   "UseZeroBroadcast"=dword:0  
   "IpAddress"="192.168.0.2"  
   "Subnetmask"="255.255.255.0"  
設 置之後要生效有兩種辦法:一種熱啓動,調用KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0,  NULL),熱啓動時間很短暫;另外一種調用DevieceIoControl API,傳遞IOCTL= IOCTL_NDIS_REBIND_ADAPTER。  
  
如何向控制面板中那樣,修改系統聲音的音量  
調用API waveOutSetVolume(HWAVEOUT, dwVolume ),一般參數1爲0。在[HKEY_CURRENT_USER//ControlPanel//Volume]下是系統聲音的註冊表設置。  
  
在應用程序中如何實現jpg、gif圖片的顯示  
有幾種辦法:  
1、 在MSDN中搜索標題爲“Windows CE .NET Technical Frequently Asked Questions”的文檔,其中有一個問題“How can I display JPEG, GIF, and other graphics files?”,下面就是答案。  
2、如果安裝了Windows CE 5.0,一個例子源碼位於WINCE500//PUBLIC//GDIEX//SDK//SAMPLES//SIMPLE。  
3、用IWebBrowser組件實現。  
  
     在應用程序中如何實現系統待機  
void GwesPowerOffSystem(void);  
  
     在WINCE下如何實現鍵盤鉤子  
我寫了一個簡單的例子,把其中主要部分截取出來放到了我的FTP裏。用戶名以及密碼均爲winceuser,地址是ftp://211.95.73.26/[email protected]/SourceCode/ 用鉤子禁止系統鍵.rar。  
  
     在WINCE中如何得到網卡MAC地址  
事 實證明,獲得物理網卡的MAC地址並沒有被統一成一個API或者IOCTL,如果網卡驅動程序沒有提供接口的話只能直接訪問寄存器獲得。讀者可以參考目錄 WINCE500//PUBLIC//COMMON//OAK//DRIVERS//NETCARD裏的一些驅動源碼。  
  
Windows XP Embedded 和Windows CE有何區別  
簡 單地說Windows XP Embedded採用Windows XP內核,只能運行在x86處理器上,優點是能夠運行PC上現有的應用軟件,缺點是授權費太高,標價¥900元;Windows CE採用Windows CE內核,能夠運行在多種處理器上,如x86、ARM、SHX、MIPS等,優點是授權費低,最低Core版標價¥30元。缺點是需要單獨開發應用軟件、 定製內核,甚至開發BSP、Driver。  
  
     wince下只是把調制解調器的驅動掛接在了com1,如何將器驅動掛接在com2上?  
1、 在HLM//drivers//buildin//com2//unimodem下複製和com1一樣的數據 2、在HLM//ExtModems// HayesCompat下改寫Port爲COM2:,再改寫FriendlyName爲"Hayes Compatible 在 COM2:"。  
  
如何定製自己的外殼  
1、先開發一個外殼軟件,假設名稱爲MyShell.exe  
2、刪除註冊表[HKEY_LOCAL_MACHINE//init]下如下一行:  
   "Launch50"="explorer.exe"  
3、在註冊表[HKEY_LOCAL_MACHINE//init]下添加如下一行:  
   "Launch50"="MyShell.exe"  
上述的“LaunchXX”中的XX爲序列數,內核依據這個序列數按由小到大的順序來分別執行所有子鍵列出的應用程序,具體數值應該爲多少請參考幫助文檔的說明。  
如果原來的內核中添加了標準外殼(standard shell)組件,或者添加了其它組件而這些組件需要依賴標準外殼,那麼在PB中是無法刪除標準外殼組件的,解決辦法一是保留explorer.exe在內核中,二是刪除依賴標準外殼的組件。  
  
     我原來的工程是x86版本的,編譯選項只有x86,我如何能夠編譯ARM版本的  
兩種辦法:  
1、用EVC新建一個工程的時候,建議複選“CPUs”列表,這樣發生了這種事情也能夠輕易通過選擇“WCE Configuration”工具欄中的CPU列表來編譯不同CPU版本的軟件  
2、如果打開工程後CPU列表中只有x86,而此時已經安裝了ARM版本的SDK,那麼單擊EVC菜單“build”-“configurations”,然後單擊“add”按鈕來添加CPU。  
  
     通常情況下WINCE採用串口1作爲調試時輸出信息用途,要正式出產品前如何去掉串口1的調試功能  
正 常情況下串口1只有在編譯debug版本的內核時纔在BootLoader中初始化串口1用於輸出信息,而編譯release版本會跳過此代碼。而有些 BSP設計成沒有宏定義,也就是說無論什麼版本都會在BootLoader中初始化串口1,這樣造成WINCE啓動後串口1無法被應用程序使用。對於這種 情況只能在BootLoader源碼中刪除初始化代碼,如OEMInitDebugSerial。  
  
     我怎麼能在PB左邊的定製平臺加進我的驅動呢?  
兩種辦法:  
1、在platform.bib或者project.bib的MODULES部分添加一條語句,例如:  
MyDriver.dll       C://Driver//MyDriver.dll                     NK SH  
這樣編譯內核的時候就會把你的驅動DLL文件添加到內核中,如果有註冊表需要設置,在platform.reg或者project.reg中添加註冊表內容。  
2、通過製作.cec文件來添加驅動,製作.cec文件的優點是隻需製作一次,以後就可以通過將.cec文件導入到PB的Catalog中,象PB自帶的feature一樣通過菜單“Add to OS Design”添加到左邊的內核工程中。  
  
     WINCE有沒有相對路徑概念?如果沒有如何得到當前模塊的路徑?  
1、WINCE沒有相對路徑概念,只有絕對路徑,所以凡是涉及到路徑均爲絕對路徑。  
2、調用API GetModuleFileName,傳遞一個模塊的實例句柄就能夠得到模塊的絕對路徑。  
  
     怎樣讓 POCKET WORD打開*.dat格式(裏面都是數據)的文件?  
兩種辦法:  
1、調用API ShellExecuteEx,在結構體SHELLEXECUTEINFO中添加.dat文件的路徑。  
2、調用API CreateProcess,在第二個參數中設置.dat文件的路徑。  
    
  
GWES組件的功能有哪些?  
GWES不僅負責GDI、窗口、消息,還負責管理本機設備驅動程序,負責加載顯示、鍵盤鼠標、觸摸屏驅動程序,而且GWES本身包含電源、LED驅動程序。  
  
如何在PB中預先設定好存儲內存和程序內存的大小,我想多劃分一些空間給程序內存?  
兩種辦法:  
1、在定製內核時在config.bib文件中設置FSRAMPERCENT = number,具體number可參考標題爲“FSRAMPERCENT ”的幫助文檔。這種辦法是修改內核的設置,所有一直有效。  
2、在應用程序中調用API SetSystemMemoryDivision,如果函數返回SYSMEM_CHANGED表示成功,如果返回SYSMEM_MUSTREBOOT表示需要熱啓動纔能有效。這種辦法需要每次啓動後調用API纔有效。  
  
如何取消鼠標光標?  
通過取消SYS變量來實現此目的,在PB命令行下鍵入“set SYSGEN_CURSOR=”,然後回車確認。  
  
EVC下調用TextOut如何編譯會出錯?  
類 似這樣的問題很多,這是因爲EVC的幫助文檔內容有錯誤。可能EVC的幫助文檔內容是從桌面Windows幫助文檔複製過來的,所以很多API函數還有例 子代碼都有錯誤,例如幫助文檔中包含一個API函數的說明,但是實際編譯的時候提示沒有這個API,有的例子代碼採用ANSI字符串,而WINCE的 API都是寬字符版本,造成直接複製過來編譯失敗。  
因爲MFC for WINCE的CDC類中沒有TextOut成員函數,所以編譯會出錯,可以用其它類成員函數ExtTextOut或者DrawText替換。  
  
我如何將我的dll軟件讓現有的ce系統認可?儘管我也知道應該使用signfile.exe程序進行簽名,但是我並不知道那個ce系統認可的簽名應該是啥  
如果你說的WINCE系統內核已經加入了簽名認證機制,那麼沒有私鑰對你的DLL文件簽名肯定是無法運行在此內核中的,一般簽名密鑰的密鑰長度都是1024位,很難破解。  
  
如果查看WINCE註冊表中的內容?  
兩種辦法:  
1、建立同步後,用EVC自帶的工具“Remote Registry Editor”打開查看。  
2、從網上下載註冊表查看工具,放到WINCE設備中。  
  
調用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或者其它組件。  
  
     在PB的config.bib文件中,“IMGFLASH”表示什麼意思呢?  
表示能夠刷NK到ROM中,具體請查看標題爲“IMG Environment Variables”的幫助文檔。  
  
     驅動程序如何發通知給應用程序?  
這裏介紹一下常見的兩種辦法。  
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。  
  
  
如何讓系統加載自己寫的驅動程序?  
兩種辦法:  
1、在[HKEY_LOCAL_MACHINE//Drivers//BuiltIn]下添加註冊鍵。  
2、在應用程序中調用ActivateDeviceEx。  
  
在一些文件中用分號來表示註釋,例如下面的內容  
; @CESYSGEN IF SERVERS_MODULES_HTTPD  
; @CESYSGEN ENDIF  
在“CESYSGEN...”前加了“@”,有沒有什麼特別的含義?  
在WINCE的一些文件中,用“;”作爲註釋並在註釋文字中用@CESYSGEN作爲標記,後面接條件語句。Cefilter.exe工具負責按照條件來篩選文件內容,所以不要輕易地刪除包含@CESYSGEN的註釋語句。  
  
通過串口建立ActiveSync聯接,串口線用三線的可以嗎?  
不可以,因爲用串口同步時要用到其餘口的狀態。  
  
     WINCE是否支持MAPI?  
不支持。WINCE自帶的pmail.exe軟件也不是很好用。建議自開發郵件收發軟件。如果需要購買WINCE下郵件收發軟件可以聯繫我。  
  

<!--v:2.2-->

--  作者:admin
--  發佈時間:2009-3-6 14:28:33
--  
如何旋轉屏幕顯示的內容?  
例子代碼如下(前提是顯示驅動程序支持旋轉):  
DEVMODE  devmode = {0};  
devmode.dmSize = sizeof(DEVMODE);  
devmode.dmDisplayOrientation = DMDO_90;       ///垂直模式  
devmode.dmFields = DM_DISPLAYORIENTATION;  
ChangeDisplaySettingsEx(NULL, &devmode, NULL, 0, NULL);  ///改變顯示的設置  
CRect  rcWorkArea(0, 0, 320, 240);    ///整個屏幕尺寸  
///設置客戶區大小並廣播消息,這樣所有軟件也就隨之更改顯示  
SystemParametersInfo(SPI_SETWORKAREA, 0, (void*)&rcWorkArea, SPIF_SENDCHANGE);  
  
請問如何修改字形緩存的容量?  
[HKEY_LOCAL_MACHINE//System//GDI//GLYPHCACHE]  
"limit"=dword:0400  
  
如何得到從WINCE啓動開始到現在的時間?  
調用API GetTickCount,得到的值爲32位整數,單位爲毫秒。  
  
如何調用WINCE的軟鍵盤?  
調用API SipShowIM(SIPF_ON),前提是內核加入了軟鍵盤組件。  
  
基於HIVE的註冊表,如何在系統關閉前保存註冊表的數據到文件system.hv?  
調用API RegFlushKey函數。  
  
使用VirtualAlloc和VirtualCopy的時候需要注意哪些事項?  
1、 VirtualAlloc的作用是申請虛擬地址空間,這肯定不是最終的目的,最終目的可能是申請物理內存、映射寄存器、提交文件等。沒有一個目的會在意虛 擬地址空間的位置,所以儘量傳遞參數1爲0,也就是讓WINCE自動分配虛擬地址空間。VirtualAlloc分配地址空間實際上是以64KB爲單位, 所以要指定申請的虛擬空間的首地址的話,參數1應該爲64KB的整數倍,申請的長度也應該爲64KB的整數倍,即使你不需要那麼大。  
2、 VirtualCopy的主要作用是映射物理地址空間,如果參數2爲物理地址,那麼最後一個參數要添加PAGE_PHYSICAL,參數2必須是256的 整數倍。如果參數2爲虛擬地址(0x80000000以上),那麼最後一個參數就不要添加PAGE_PHYSICAL,WINCE內核會根據這個虛擬地址 找到對應的物理地址。  
  
驅動程序和應用程序之間傳遞數據時何時調用MapPtrToProcess?  
因爲設備管理器負 責加載驅動程序DLL,這意味着當應用程序調用驅動程序接口函數的時候,WINCE內核會將調用驅動程序接口函數的線程轉移到設備管理器的進程空間然後執 行具體的驅動程序代碼,應用程序和設備管理器處於兩個進程空間,這就造成設備管理器無法訪問應用程序傳遞的指針(虛擬地址),所以當我們在應用程序中傳遞 指針給流驅動程序接口函數時,WINCE內核從中作了一個地址映射,例如ReadFile、WriteFile、DeviceIoControl函數的參 數凡是指針都經過了映射才傳遞給驅動程序,所以很多驅動程序開發者並不瞭解其中的奧祕就可以編程了。但是如果參數是一個指向一個結構體的指針,而結構體裏 包括一個或多個指針,那麼WINCE內核並不負責映射,所以就需要開發者在驅動程序接口函數中調用API函數MapPtrToProcess來映射地址。 例如:pPointer_retval = MapPtrToProcess(pPointer, GetCallerProcess());  
  
如何判斷可插拔的設備是否存在?  
1、 通過查找註冊表的值。凡是由API ActivateDeviceEx加載的驅動程序都在[HKEY_LOCAL_MACHINE//Drivers//Active]鍵下有註冊鍵,通過查 找“name”或者其它鍵值就能夠找到。設備管理器就調用這個API。如果是PCI設備,在註冊表[HLM//Drivers//BuiltIn //PCI//Instance]下查找關鍵字,例如[HLM// Drivers//BuiltIn//PCI//Instance//WaveDev1],說明音頻驅動已經加載。  
2、調用驅動程序接口函數,根據返回值或者執行結果來判斷。  
  
如何做到通過串口過來的一個信號啓動自己開發的應用程序?  
創 建一個線程負責等待串口過來的信號,調用API SetCommMask設置要等待的信號種類,具體可以等待的信號種類參見參數2的說明。然後再調用 API WaitCommEvent函數等待這個信號,接收之後再調用API CreateProcess啓動應用程序。  
  
在WINCE中如何只能啓動應用程序的一個實例?  
常用的兩種辦法:  
1、如果應用程序實例創建了窗口,可通過API FindWindow函數通過窗口類名和窗口標題名稱來查找,前提是系統內不會出現窗口名稱重複的情況。  
2、應用程序初始化的時候創建一個事件或互斥等內核對象,因爲內核對象是由內核創建,名稱在系統內唯一。  
  
能不能自己編輯一個數字簽名文件導入到手機上,這樣就可以用這個簽名籤自己的程序了?  
WINCE的內核簽名機制的用途是限制非法的可執行模塊EXE、DLL等在設備上運行。要求內核的加載模塊用公鑰驗證請求加載的EXE、DLL的簽名是否合法,而這個公鑰是在定製內核的時候加進去的,所以除內核的定製者以外的人無法修改這個驗證機制。  
  
我按照版主的文章《加密WINCE系統》裏操作,提示錯誤如下:  
Error 80090016 during CryptSignHash 1!  
Error signing hash  
這 是因爲傳遞了無效的鑰容器名稱,使CryptoAPI調用失敗。應該在使用signfile工具之前創建一個鑰容器,在桌面Windows中調用 API CryptAcquireContext創建一個指定名稱的鑰容器,接着再創建一個簽名密鑰對,這時再使用signfile工具就可以了。我在文章裏寫成 -kfulinlin是因爲我創建鑰容器的時候沒有指定名稱,系統就採用當前登錄的用戶名爲容器名。  
  
編譯錯誤:CVTRES : fatal error CVT1102: out of memory; 42 bytes required ?  
多 數情況下出現這種錯誤是因EVC的bug而起,應該在安裝EVC之後就立刻安裝EVC的SP補丁。另外爲了避開BUG,使用EVC編程應該養成一些習慣, 比如定期備份工程所有文件,每次編譯時採用Clean + Rebuild All,正調試時不要關閉模擬器等等。  
  
在WINCE下是否能夠得到某一進程使用的物理內存總量?  
目前沒發現有這樣一個API能夠得到指定進程使用的物理內存總量。只有GlobalMemoryStatus能夠得到整個系統使用的物理內存總量。  
  
應用程序如何控制lcd的亮度?如何獲得電池的電量?  
從 常見的平臺如Geode、三星ARM系列來看,的確在驅動方面沒有統一的控制LCD或者其它種類屏幕亮度的接口函數,所以只能根據具體平臺提供的接口來 做。從幫助文檔來看微軟的帶有DirectDraw功能的顯示驅動程序的確有標準的增加亮度的接口函數,關於背景光參見標題爲 “Enabling a Backlight”的幫助文檔。  
獲得電池電量有標準的接口函數GetSystemPowerStatusEx,前提是驅動程序和硬件都要支持。  
  
WINCE的socket函數好像不支持發送/接收超時?  
是的,最早版本的WINCE支持選項SO_RCVTIMEO、SO_SNDTIMEO,後來卻不支持了。  
  
WINCE下如何設置窗口最大化和最小化?  
WINCE 的幫助文檔在介紹API ShowWindow函數的參數時指出SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE,  SW_SHOWDEFAULT, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE都不被支持,但實際上並不完全是這樣,具體來說:  
SW_MAXIMIZE            比原來窗口大,但不是最大化  
SW_MINIMIZE             編譯成功,但是不起作用  
SW_SHOWMAXIMIZED     最大化  
SW_SHOWMINIMIZED      編譯出錯  
SW_RESTORE              能恢復  
SW_SHOWDEFAULT        編譯出錯  
SW_SHOWMINNOACTIVE   編譯出錯  
SW_HIDE                  能夠隱藏  
  
如何用程序調用控制面板的觸摸屏校對程序?  
兩種辦法:  
1、調用API TouchCalibrate函數  
2、調用CreateProcess,參數1爲L"////windows////ctlpnl.exe",參數2爲L"cplmain.cpl,9"。  
  
如何獲得U盤或者其它類型的存儲器總容量和剩餘可用容量?  
調用API GetStoreInfo得到扇區數、每扇區字節數,相乘即是總容量。調用API GetDiskFreeSpaceEx得到剩餘可用容量。  
  
  
基於RAM的註冊表如何保存數據?  
調用API RegCopyFile備份註冊表。調用API RegRestoreFile恢復註冊表,然後調用KernelIoControl熱啓動使恢復生效。  
  
如何隱藏和顯示winCE下標準外殼的任務欄?  
HANDLE  hTaskBar = FindWindow(L"HHTaskBar", NULL);  
ShowWindow(hTaskBar, SW_HIDE);  
ShowWindow(hTaskBar, SW_SHOWNORMAL);  
  
  wince下如何讓操作系統進入待機模式?又如何把它激活?  
通過註冊表就可以設置,前提是你的驅動和硬件都支持。註冊表項參見標題爲“GWES Suspend Time-outs”的幫助文檔。  
[HKEY_LOCAL_MACHINE//System//CurrentControlSet//Control//Power]  
    "BattPowerOff"=dword:300  
    "ExtPowerOff"=dword:0  
    "WakeupPowerOff"=dword:60  
    "ScreenPowerOff"=dword:0  
  
[此貼子已經被作者於2009-3-6 14:29:09編輯過]

--  作者:admin
--  發佈時間:2009-8-20 14:10:57
--  
在WINCE中如何只能啓動應用程序的一個實例? 常用的兩種辦法: 1、如果應用程序實例創建了窗口,可通過API FindWindow函數通過窗口類名和窗口標題名稱來查找,前提是系統內不會出現窗口名稱重複的情況。 2、應用程序初始化的時候創建一個事件或互斥等內核對象,因爲內核對象是由內核創建,名稱在系統內唯一。 能不能自己編輯一個數字簽名文件導入到手機上,這樣就可以用這個簽名籤自己的程序了? WINCE的內核簽名機制的用途是限制非法的可執行模塊EXE、DLL等在設備上運行。要求內核的加載模塊用公鑰驗證請求加載的EXE、DLL的簽名是否 合法,而這個公鑰是在定製內核的時候加進去的,所以除內核的定製者以外的人無法修改這個驗證機制。 我按照版主的文章《加密WINCE系統》裏操作,提示錯誤如下: Error 80090016 during CryptSignHash 1! Error signing hash 這是因爲傳遞了無效的鑰容器名稱,使CryptoAPI調用失敗。應該在使用signfile工具之前創建一個鑰容器,在桌面Windows中調用API CryptAcquireContext創建一個指定名稱的鑰容器,接着再創建一個簽名密鑰對,這時再使用signfile工具就可以了。我在文章裏寫成 -kfulinlin是因爲我創建鑰容器的時候沒有指定名稱,系統就採用當前登錄的用戶名爲容器名。 編譯錯誤:CVTRES : fatal error CVT1102: out of memory; 42 bytes required ? 多數情況下出現這種錯誤是因EVC的bug而起,應該在安裝EVC之後就立刻安裝EVC的SP補丁。另外爲了避開BUG,使用EVC編程應該養成一些習 慣,比如定期備份工程所有文件,每次編譯時採用Clean + Rebuild All,正調試時不要關閉模擬器等等。 在WINCE下是否能夠得到某一進程使用的物理內存總量? 目前沒發現有這樣一個API能夠得到指定進程使用的物理內存總量。只有GlobalMemoryStatus能夠得到整個系統使用的物理內存總量。 應用程序如何控制lcd的亮度?如何獲得電池的電量? 從常見的平臺如Geode、三星ARM系列來看,的確在驅動方面沒有統一的控制LCD或者其它種類屏幕亮度的接口函數,所以只能根據具體平臺提供的接口來 做。從幫助文檔來看微軟的帶有DirectDraw功能的顯示驅動程序的確有標準的增加亮度的接口函數,關於背景光參見標題爲“Enabling a Backlight”的幫助文檔。 獲得電池電量有標準的接口函數GetSystemPowerStatusEx,前提是驅動程序和硬件都要支持。 WINCE的socket函數好像不支持發送/接收超時? 是的,最早版本的WINCE支持選項SO_RCVTIMEO、SO_SNDTIMEO,後來卻不支持了。 WINCE下如何設置窗口最大化和最小化? WINCE的幫助文檔在介紹API ShowWindow函數的參數時指出SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWDEFAULT, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE都不被支持,但實際上並不完全是這樣,具體來說: SW_MAXIMIZE 比原來窗口大,但不是最大化 SW_MINIMIZE 編譯成功,但是不起作用 SW_SHOWMAXIMIZED 最大化 SW_SHOWMINIMIZED 編譯出錯 SW_RESTORE 能恢復 SW_SHOWDEFAULT 編譯出錯 SW_SHOWMINNOACTIVE 編譯出錯 SW_HIDE 能夠隱藏 如何用程序調用控制面板的觸摸屏校對程序? 兩種辦法: 1、調用API TouchCalibrate函數 2、調用CreateProcess,參數1爲L"////windows////ctlpnl.exe ", 參數2爲L"cplmain.cpl,9"。 如何獲得U盤或者其它類型的存儲器總容量和剩餘可用容量? 調用API GetStoreInfo得到扇區數、每扇區字節數,相乘即是總容量。調用API GetDiskFreeSpaceEx得到剩餘可用容量。 三星2440頭文件定義#define IIC_BASE 0xB1400000 // 54000000,datasheet是54000000,那麼怎麼轉成0xB1400000? 物理地址映射方法分爲兩種,一種靜態映射另一種爲動態映射。在OEMAddressTable中定義了物理地址與虛擬地址的映射關係屬於靜態映射,用 VirtualCopy映射屬於動態映射,採用哪種辦法都可以。問題中提到的屬於靜態映射,2440的BSP在map.a文件中定義了IIC控制寄存器的 物理起始地址和對應的虛擬地址如下: DCD 0x91400000, 0x54000000, 1 ; 在OEMAddressTable中定義的虛擬地址範圍在0x8000 0000—0x9FFF FFFF,這部分可緩存,適合內核程序和應用程序使用,同時WINCE內核在0xA000 0000—0xBFFF FFFF中映射了另一份,指向了同樣的物理地址,這部分不可緩存,適合驅動程序使用。三星ARM處理器帶有L1級高速緩存,可緩存會提高執行效率。對於特 殊的設備寄存器適合映射到不可緩存的虛擬地址。 當驅動程序調用VirtualCopy對0xB1400000地址讀寫時,WINCE自動將這個地址減去0x2000 0000,也就是0x91400000,對應的物理地址就是0x54000000,也就是IIC控制寄存器的物理起始地址。 基於RAM的註冊表如何保存數據? 調用API RegCopyFile備份註冊表。調用API RegRestoreFile恢復註冊表,然後調用KernelIoControl熱啓動使恢復生效。 如何隱藏和顯示winCE下標準外殼的任務欄? HANDLE hTaskBar = FindWindow(L"HHTaskBar", NULL); ShowWindow(hTaskBar, SW_HIDE); ShowWindow(hTaskBar, SW_SHOWNORMAL); 如果能讓WINCE的IE瀏覽器播放flash動畫? 播放flash需要Macromedia Flash Player SDK,參見http://www.adobe.com/products/flashplayer_sdk/。這和real player相似,都需要WINCE平臺的SDK,都需要申請。 WINCE下內核模式和用戶模式有什麼區別? 爲了使讀者能夠詳細瞭解WINCE的地址映射原理還有兩種模式,在這裏我分幾個部分說明: 1、WINCE內核nk.exe的任務是管理操作系統核心功能。按照OEMAddressTable的映射要求,所有物理地址都映射到 0x80000000以上,所以對於內核程序nk.exe和內核模式下的線程來說,只要訪問0x80000000以上的有效虛擬地址經MMU就能夠訪問物 理地址,無需再映射是內核模式的一個特點。內核模式的第二個特點是沒有地址訪問限制,內核模式線程可以訪問任何有效虛擬地址,所謂有效虛擬地址是指有實際 事物對應。 2、用戶模式線程只能訪問0x80000000以下的虛擬地址空間,WINCE6.0之前版本的內核爲每個進程劃分32MB的地址空間,在不調用特殊函數 的情況下不能相互訪問,這樣的設計使得WINCE系統更安全、更穩定,限制訪問地址是用戶模式的第一個特點。第二個特點就是需要多一層映射,如果線程要訪 問物理內存的話需要先映射到0x80000000以上,再經MMU訪問物理內存地址。 WINCE的線程具有轉移性(參考API GetCallerProcess的說明,有一個很好的例子),當應用程序的線程調用API或者調用驅動程序接口函數時,該線程會轉移到 gwes.exe、device.exe、filesys.exe等進程中執行,轉移是由WINCE內核操作的,它會修改線程的上下文,記錄線程的當前進 程、調用者進程、擁有者進程三個值。 3、如果在定製內核的時候選擇了“Full Kernel Mode”,那麼在這個內核上運行的所有線程都處於內核模式,即使調用SetKMode(FALSE)後線程仍然具有內核模式的特點,能夠訪問任何有效的 虛擬地址。假設現有一個64MB RAM的WINCE產品,RAM映射從0x80000000到0x84000000,如果線程處於內核模式,它就直接可以訪問這個範圍的虛擬地址: 在OnButton1()中編寫 代碼: DWORD oldMode = SetKMode(FALSE); volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000) *piTemp = 12345; 在OnButton2()中編寫 DWORD oldMode = SetKMode(FALSE); volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000) int iTemp = *piTemp; 先只執行OnButton1()然後關閉程序,再重啓程序然後執行OnButton2(),iTemp仍然等於12345。結果說明了兩點:內核模式線程 可以直接訪問0x80000000以上的有效虛擬地址;我們寫到RAM中的數據沒有丟失,說明虛擬地址有效。 如果在定製內核的時候沒有選擇“Full Kernel Mode”,那麼在這個內核上運行的所有線程都處於用戶模式。可以調用SetKMode(TRUE)使調用線程暫時處於內核模式,還是原來的假設環境,我 再舉個例子: 在OnButton1()中編寫 DWORD oldMode = SetKMode(TRUE); volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000) *piTemp = 12345; 在用戶模式下,如果不調用SetKMode(TRUE),那麼執行*piTemp = 12345一定會彈出對話框,提示地址訪問非法,如果調用SetKMode(TRUE)就不會提示地址訪問非法,而且在OnButton2()中仍然能得 到12345這個值。 通過這兩個例子我相信讀者能夠完全瞭解兩種模式的區別了。 4、WINCE提供了兩個函數SetKMode和SetProcPermissions,其中SetKMode能夠把調用線程切換到內核模式,還可以切換 回用戶模式。SetProcPermissions + GetCurrentPermissions添加當前進程訪問權限給調用線程,SetProcPermissions (0xFFFFFFFF)能讓調用線程訪問所有進程空間,但是調用線程仍然處於用戶模式。SetKMode和SetProcPermissions函數使 得用戶模式的特點不那麼明晰。 如上所說一個應用程序的線程可能轉移到其它兩個進程地址空間中讀寫數據,而每一個線程在被創建的時候只有訪問創建它的進程地址空間的權限,所以驅動程序開 發者必須在驅動程序讀寫數據前調用SetKMode或者SetProcPermissions增加調用此函數的線程訪問其它進程空間的權限。如果一個應用 程序的線程只轉移到一個進程地址空間,一般爲設備管理器進程device.exe,這種情況下不必增加線程訪問其它進程空間的權限,但如果驅動程序本身創 建了一個線程,那還是要調用SetKMode或者SetProcPermissions增加新的線程訪問其它進程的權限的,因爲驅動程序創建線程時,當前 進程爲設備管理器,所以新線程只具有訪問設備管理器進程空間的權限,而不具備訪問應用程序進程空間的權限。 5、可能一個編寫過簡單的流驅動的初學者會很疑惑,因爲開發一個簡單的流驅動程序根本不需要調用這些函數,也沒有調用過MapPtrToProcess, 那是因爲如果標準流驅動接口函數的參數爲指針(ReadFile、WriteFile、DeviceIoControl參數都有指針),WINCE內核會 自動映射指針包含的地址,但僅此而已,其餘任何情況都要求開發者自行處理,比如流接口函數的參數是一個指向結構體的指針PA,而結構體中包括指針 PB,PB指針就必須在流接口函數中映射,映射後才能訪問,否則就會造成地址訪問非法。所以結構體中每個指針都要映射。 爲了讓讀者能瞭解其中的原因,我舉個例子: 假設設備管理器被加載到Slot4,應用程序A被加載到Slot 8,A只有一個主線程T,T開始執行,按照WINCE的規定,正獲得CPU的進程必須映射到Slot0,那麼在執行代碼的時候A的所有虛擬地址都被減去一 個偏移值,也就是8×0x02000000,A調用DeviceIoControl,傳遞一個指向一個結構體的指針B,而這個結構體中包含一個指針C,指 針C包含的地址假設爲0x00030000,當執行DeviceIoControl時WINCE把設備管理器的進程地址空間映射到Slot0,因爲放在注 冊表[HKLM//Drivers//BuiltIn]下的驅動程序是由設備管理器加載的,自然驅動程序的代碼段被加載到設備管理器進程空間,但是線程仍 然是T,此時T的當前所在進程爲設備管理器(CurrentProcess),A變成了T的調用者進程(CallerProcess),T自動具有了訪問 調用者進程空間的權限。這時訪問Slot0中的虛擬地址其實質就是訪問設備管理器的進程地址空間,要把地址加上一個偏移值,也就是 4×0x02000000,所以DeviceIoControl訪問指針C包含的地址時本應該加上8×0x02000000,卻加上 4×0x02000000,結果地址並不是設備管理器的合法區域,系統就會提示地址訪問非法。而如果做了一個映射,指針C包含的地址就會被加一個正確的偏 移值,使地址處於A的地址空間Slot 8中,T此時具有訪問A進程空間的權限,訪問到正確的虛擬地址當然會得到正確的數據了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章