您的位置:首页 > 其它

Windows CE开发常见问题解答

2010-12-31 20:32 267 查看
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 [b]InitCommonControlsEx
function, which registers a specific set of common control classes. Calling InitCommonControlsEx
ensures that the common DLL is loaded.[/b]

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/fllsoft@sina.com/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进程空间的权限,访问到正确的虚拟地址当然会得到正确的数据了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息