分类: 嵌入式
2011-04-01 09:00:07
这是我在做wince6的时候为设置自启动而寻找的方法。我发现公司定的这个设备在“Program Files”和windows文件夹下放置的东西在机子重启之后就什么都没有了。我只有使用注册表测试,发现重启后还存在,因此我用注册表方式设置了自启动。而在这个过程中,我发现如果程序放在SD卡内是不行的,只有放在nand才行。为什么放在SD卡内不可以自启动,原因在我下面搜集的几篇文章中找到了,原来SD卡是在自启动程序之后才加载了驱动运行起来的。
wince 自动启动程序设置
修改注册表[HKEY_LOCAL_MACHINE\init] |
如何让应用程序随wince操作系统自启动
如何让应用程序随wince操作系统自启动呢?我搜索了一下,网上有不少方法,但有时也会有疏漏的地方,通常一点小小的错误也会导致整个环节不能进行下去。在此,我想跟大家共同探讨一下,欢迎大家指正。
首先,假设你的应用程序为:MyApp.exe。
方法一:主要思想:将应用程序及其快捷方式也添加到映像里,再将快捷方式添加到StartUp目录下,这样当系统运行后应用程序就能自动运行。
步骤:
1先保证原工程文件是可以编译成功的。假设编译好的nk.bin文件所在文件夹为xxx_Relase。
2创建快捷方式文件MyApp.lnk,文件内容如下:
10#”\Windows\MyApp.exe”(注意引号)
3在pb中修改project.bib文件,在FILES Section添加:
MyApp.exe $(_FLATRELEASEDIR)\MyApp.exe NK H
MyApp.lnk $(_FLATRELEASEDIR)\MyApp.lnk NK H
(注:$(_FLATRELEASEDIR)表示xxx_Relase文件夹;NK后面的H表明加入到nk.bin中的文件为隐藏属性)
4 把快捷方式添加到StartUp目录下,具体为:
修改工程的project.dat文件,添加如下内容:
Directory("\Windows\Startup"):-File("MyApp.lnk","\Windows\MyApp.lnk")
5从道理上讲,如果这时把MyApp.exe和MyApp.lnk拷贝到xxx_Relase文件夹下,然后Build->MakeImag的话就会把你的应用程序添加到NK里,但实际情况并非如此,经我实验,先要把工程文件全部rebuild一下,我这儿是sysgen了一下,如果你设置了在编译完后MakeImage 的话,会有错误提示你未在你的磁盘上找到MyApp.exe。不用管它。把MyApp.exe和MyApp.lnk文件拷贝到xxx_Relase文件夹下,然后MakeImage一下(记住此时千万不能再rebuild了,否则会前功尽弃),把生成的NK.bin烧写到flash里,这样就可以看到你的应用程序MyApp.exe自启动了.
方法二:主要思想:将应用程序添加到映像里,然后用你的应用程序直接替换Wince的桌面程序。
步骤:
1. 像方法一一样把你的应用程序添加到映象里。
提示:要查看添加映象是否成功,可以在操作系统启动后,看一下windows目录下是否有你的应用程序MyApp.exe(先要设置为可以查看系统文件和隐藏文件)。
2.修改shell.reg(若在pb里找不到,可以到xxx_Relase文件夹下找):
[HKEY_LOCAL_MACHINE\init]
"Launch50"="explorer.exe"
"Depend50"=hex:14,00, 1e,00
把这个explorer.exe改成你的应用程序(比如:MyApp.exe)。
3. MakeImage一下(还是记住不能再build了),把生成的NK.bin烧写到flash里,这样就可以看到你的应用程序MyApp.exe自启动了.
这样做的好处是启动的时候wince的桌面程序都不会启动了,坏处是当你把应用程序关闭的时候由于原wince桌面程序的丢失而会使机器死机。
方法三:主要思想:将应用程序添加到映像里,然后修改注册表,让应用程序自启动。这回不替换wince的桌面程序,而是让wince像加载桌面一样加载你的应用程序,效果跟方法一是一样的。
步骤跟方法二是一样的,只是第二步稍有不同:
在shell.reg文件中[HKEY_LOCAL_MACHINE\init]之下添加如下语句:
"Launch80"="MyApp.exe"
"Depend80"=hex:1E,00
说明:"Depend80"=hex:1E,00用来设置启动顺序和依赖程序,若你的应用程序不依赖于其它程序,这句可以不加。
另外,应用程序也不一定就要加载到映象文件里,可以直接从u盘,硬盘,sd卡等加载,但是要先保证你的应用程序自启动时系统已能正确识别挂接的u盘,硬盘,sd卡等。
有两个地方启动程序:
1. 在注册表HKLM\Init上加入键值:Launch99="你的程序名(可以是绝对路径)",如果你的程序要依赖别的程序,还要加入:Depend99=依赖程序的启动序号(可以看看Init下其它程序的启动顺序)
2.好像是在HKLM下有个WBT,里面有个地方也可以加入启动程序,每次注销都会重新启动一遍,而Init只有在重新开机时才启动。
你要启动的程序,可以放在你的flash卡上(Init需要加入绝对路径),或者加入bib文件,编译进内核。
WinCE 应用程序开机自启动方法
近日在开发过程中遇到WinCE应用程序开机自动运行的问题,在网上找了找,发现大概有以下三种方法:
1、 将应用程序和应用程序快捷方式添加到映像里,再将快捷方式添加到StartUp目录下,这样当系统运行后应用程序就能自动运行;
2、 直接替换Wince的SHELL,即修改注册表:
[HKEY_LOCAL_MACHINE\init]
"Launch50"="explorer.exe"
"Depend50"=hex:14,00, 1e,00
把这个explorer.exe改成你的应用程序(比如:MyApp.exe);
3、 把应用程序加入到映像,修改注册表:
[HKEY_LOCAL_MACHINE\init]
"Launch80"="MyApp.exe"
"Depend80"=hex:1E,00
可以设置启动顺序和依赖程序;
以上方法都可行,但是都存在一个问题,就是应用程序是集成到NK里面的,也就是说每次升级应用程序都要重新编译下载内核,很麻烦,尤其在程序调试阶段,大家都希望把应用程序放在SD卡上,这样更新起来比较容易;据说通过第三种方法可以实现,即修改"Launch80"="MyApp.exe"为"Launch80"="\STDCard\MyApp.exe"( STDCard为SD卡目录),但是我试了一下没有成功,因为Launch80运行时SD卡的文件驱动还没有加载,找不到MyApp.exe文件。同样,采用快捷方式加载SD卡里的应用程序也不可行。
所以我采用了另一种方法,自己编了一个小程序,比如叫ShellExe.exe,将此程序加入到映像里,通过StartUp快捷方式调用ShellExe,ShellExe再去调用SD卡里的应用程序,具体实现步骤如下:
1、 在eVC下编译如下代码:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
WIN32_FIND_DATA fd;
HANDLE hd=INVALID_HANDLE_VALUE;
int iCount = 20;
while(iCount--)
{
hd=::FindFirstFile(lpCmdLine,&fd);
Sleep(500);
if(INVALID_HANDLE_VALUE!=hd) break;
}
if(0==iCount) return 0;
FindClose(hd);
SHELLEXECUTEINFO ShExeInfo={0};
ShExeInfo.cbSize=sizeof(SHELLEXECUTEINFO);
ShExeInfo.fMask=SEE_MASK_NOCLOSEPROCESS;
ShExeInfo.hwnd=NULL;
ShExeInfo.lpVerb=NULL;
ShExeInfo.lpFile=lpCmdLine;
ShExeInfo.lpParameters=L"";
ShExeInfo.lpDirectory=NULL;
ShExeInfo.nShow=SW_SHOW;
ShExeInfo.hInstApp=NULL;
ShellExecuteEx(&ShExeInfo);
return 0;
}
生成ShellExe.exe的可执行文件,此段代码主要功能是查找指定的应用程序,然后执行;下面这段代码可以保证在SD卡文件系统正确加载后才去执行应用程序;
while(iCount--)
{
hd=::FindFirstFile(lpCmdLine,&fd);
Sleep(500);
if(INVALID_HANDLE_VALUE!=hd) break;
}
文件的名称和路径由命令行参数指定:
ShExeInfo.lpFile=lpCmdLine;2、 新建一个快捷方式,如Autorun.lnk,按如下方式编辑其内容:
21#\windows\shellexe.exe \stdcard\MyApp.exe其中\stdcard\MyApp.exe应用程序的绝对路径;
3、 将MyApp.exe和Autorun.lnk添加到NK里,方法是在project.bib文件内加入如下内容:
ShellExe.exe f:\WINCE420\PBWORKSPACES\LioetEnTer\RelDir\ShellExe.exe NK S
Autorun.lnk f:\WINCE420\PBWORKSPACES\LioetEnTer\RelDir\Autorun.lnk NK S注意:ShellExe.exe的属性不能带H(隐藏).
4、 在project.dat里加入如下内容:
Directory("\Windows\Startup"):-File("Autorun.lnk","\Windows\Autorun.lnk")5、 选择Make Image生成映像(当然Build也可以,就是慢点儿),烧到FLASH里,开机运行,可以看到SD卡里的MyApp.exe被正确执行。
总结
这种方法用起来比较方便,ShellExe.exe不用每次都重新编译,只要根据应用程序路径修改Autorun.lnk即可,可以加载Flash、U盘、SD卡里的应用程序。调试及升级应用程序就不用重新烧写内核了。
WinCE自启动Shell的问题
WinCE开机即运行定制的Shell是很多系统的基本要求,有时还需要屏蔽WinCE自带的Shell。WinCE中程序的自启动,一般有两个实现方法,修改注册表和添加自启动快捷方式。修改注册表比较方便,如下:
[HKEY_LOCAL_MACHINE\init]
"Launch70"="MyApp.exe"
"Depend70"=hex:14,00,1e,00
只要将MyApp.exe打包到NK,并在platform.reg中加入上面的注册表信息,这样WinCE启动时便会自动运行该程序。但这时WinCE自带的Shell总是先出来,然后才运行MyApp.exe,为了避免这种情况,我们可以将注册表设置修改如下:
[HKEY_LOCAL_MACHINE\init]
"Launch50"="MyApp.exe"
"Depend50"=hex:14,00,1e,00
即将原来启动explorer.exe的值换为MyApp.exe。这样WinCE启动时直接进入定制的Shell,而不启动explorer.exe。但这时有可能引入了新问题,如果定制的Shell是基于MFC编写的,并且其中用到了如CFileDialog等类库时,就会出现意想不到的情况,如下图所示:
上图是在不启动Explorer.exe时,尝试导入注册表文件出现的状况截图,而在启动explorer.exe时是没有问题的。这说明CFileDialog在某种程度上依赖于explorer.exe,具体细节没研究。但说明不启动explorer.exe,基于MFC的Shell运行时就可能会出问题。所以explorer.exe必须启动,但又不能出现WinCE界面。要解决这个问题自然就想到修改explorer.exe了。WinCE5.0和WinCE6.0中,这一部分的代码都是公开的,在WinCE6.0中Shell的相关代码在C:\WINCE600\PUBLIC\SHELL\OAK\HPC\EXPLORER\MAIN目录下。
大致看了一下这一部分的代码,发现只需修改如下两个文件,就应该能实现需求。
C:\WINCE600\PUBLIC\SHELL\OAK\HPC\EXPLORER\MAIN\desktop.cpp
+ expand sourceview plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
bool CDesktopWnd::Create()
{
IShellFolder *pSHF;
FOLDERSETTINGS fs;
RECT rc;
HRESULT hr = E_FAIL;
// Get a shell folder for the desktop
hr = SHGetDesktopFolder(&pSHF);
if(hr || !pSHF)
goto Cleanup;
// create a shell view for it
hr = pSHF->CreateViewObject(NULL, IID_IShellView, (LPVOID *)&_psv);
if(hr || !_psv)
goto Cleanup;
fs.ViewMode = FVM_ICON;
fs.fFlags = FWF_DESKTOP | FWF_ALIGNLEFT | FWF_NOSCROLL;
//++changed by hjb
//将Desktop的窗口大小设为0
//SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
SetRect(&rc, 0, 0, 0, 0);
//--changed by hjb
// create the desktop's view window (no need to AddRef since CreateViewWindow does it)
hr = _psv->CreateViewWindow(NULL, &fs, (IShellBrowser *)this, &rc, &_hWnd);
if(hr || !_hWnd)
{
Release();
goto Cleanup;
}
RegisterDesktop(_hWnd);
Cleanup:
if(pSHF)
pSHF->Release();
return (hr == S_OK);
}
bool CDesktopWnd::Create()
{
IShellFolder *pSHF;
FOLDERSETTINGS fs;
RECT rc;
HRESULT hr = E_FAIL;
// Get a shell folder for the desktop
hr = SHGetDesktopFolder(&pSHF);
if(hr || !pSHF)
goto Cleanup;
// create a shell view for it
hr = pSHF->CreateViewObject(NULL, IID_IShellView, (LPVOID *)&_psv);
if(hr || !_psv)
goto Cleanup;
fs.ViewMode = FVM_ICON;
fs.fFlags = FWF_DESKTOP | FWF_ALIGNLEFT | FWF_NOSCROLL;
//++changed by hjb
//将Desktop的窗口大小设为0
//SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
SetRect(&rc, 0, 0, 0, 0);
//--changed by hjb
// create the desktop's view window (no need to AddRef since CreateViewWindow does it)
hr = _psv->CreateViewWindow(NULL, &fs, (IShellBrowser *)this, &rc, &_hWnd);
if(hr || !_hWnd)
{
Release();
goto Cleanup;
}
RegisterDesktop(_hWnd);
Cleanup:
if(pSHF)
pSHF->Release();
return (hr == S_OK);
}
C:\WINCE600\PUBLIC\SHELL\OAK\HPC\EXPLORER\MAIN\explorer.cpp
+ expand sourceview plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
DWORD WINAPI CreateTaskBar(LPVOID pEvent)
{
HANDLE hSyncEvent = *((HANDLE *) pEvent);
CTaskBar *pTaskBar = NULL;
HWND hwndTB = NULL;
pTaskBar = new CTaskBar;
//++added by hjb
//在创建任务栏时强制终止
if(pTaskBar)
{
delete pTaskBar;
SetEvent(hSyncEvent);
return 0;
}
//--added by hjb
if(!pTaskBar)
{
SetEvent(hSyncEvent);
return 0;
}
g_TaskBar = pTaskBar;
if(!pTaskBar->Register(g_hInstance))
{
g_TaskBar = NULL;
delete pTaskBar;
SetEvent(hSyncEvent);
return 0;
}
RegisterTaskBar(pTaskBar->GetWindow());
SetEvent(hSyncEvent);
DWORD dwRet = pTaskBar->MessageLoop();
delete pTaskBar;
return dwRet;
}
DWORD WINAPI CreateTaskBar(LPVOID pEvent)
{
HANDLE hSyncEvent = *((HANDLE *) pEvent);
CTaskBar *pTaskBar = NULL;
HWND hwndTB = NULL;
pTaskBar = new CTaskBar;
//++added by hjb
//在创建任务栏时强制终止
if(pTaskBar)
{
delete pTaskBar;
SetEvent(hSyncEvent);
return 0;
}
//--added by hjb
if(!pTaskBar)
{
SetEvent(hSyncEvent);
return 0;
}
g_TaskBar = pTaskBar;
if(!pTaskBar->Register(g_hInstance))
{
g_TaskBar = NULL;
delete pTaskBar;
SetEvent(hSyncEvent);
return 0;
}
RegisterTaskBar(pTaskBar->GetWindow());
SetEvent(hSyncEvent);
DWORD dwRet = pTaskBar->MessageLoop();
delete pTaskBar;
return dwRet;
}
修改完这两处后,先编译该目录,然后再重新编译整个系统(执行Sysgen)应该就可以了。Explorer.exe依然启动,依然可以听到WinCE启动的声音,但WinCE的界面已经屏蔽掉了。此时,基于MFC的Shell也能正常工作,如下图所示:
在实际操作时,我没有通过修改源代码编译来完成这个测试。因为在编译C:\WINCE600\PUBLIC\SHELL\OAK\HPC\EXPLORER\MAIN目录时,发现它只生成了explorer.lib。考虑到重新编译整个系统的时间太长,所以直接修改了工程目录下的explorer.exe的文件,MakeImg后测试的。这里应该有快速编译的方法,但目前不知怎么弄。
修改后,在WinCE6.0的模拟器中测试,达到了预想的效果。这样就大概解决了基于MFC的Shell和Explorer.exe之间的矛盾,是不是有隐患还不清楚,目前看来没问题。
另外需要注意,修改public和private目录下的文件时,一定先做好备份,以免后患。
修改后的WinCE6.0的explorer.exe及演示视频的下载地址:
http://files.cnblogs.com/we-hjb/WinCE_Shell.rar
引用网址:http://www.cnblogs.com/we-hjb/archive/
HKEY_LOCAL_MACHINE\init\Launch80="\nandflash\em9161_xwj.exe"
[PB操作使用技巧]WinCE下直接启动应用程序的方法
其实让一个程序在wince里启动和windows里差不多,直接设置其为启动项,这个有几个方法。一个就是制作一个快捷方式,指向我们的应用程序如app.exe,然后将快捷方式放到\windows\startup下面。
步骤如下:(假设app.exe已经拷贝到windows下面)
1 在pb中创建一个文件,文件类型选txt,然后命名为.lnk后缀,假设名字为test.lnk
2 编辑其内容为: 16#\windows\app.exe。备注:前面的16是# 后面所有字符的总和,包括空格。Wince的帮助文档上说这么定义就行,但是我尝试后,最后down到目标机上面时提示找不到文件,在wince里查看这么创建的test.lnk的属性,发现其指向\windows\app.exe后面还有两个方框,因此不对,我的解决方法是修改test.lnk的内容为16#"\Windows\app.exe"
3 编辑好lnk文件内容后在pb中修改project.bib。在files段后面添加下面一行:(和添加别的文件到image中类似,见我的《WinCE中如何向image中添加文件》,也要在pb的flatform菜单的setting下添加build语句,不再赘述)
test.lnk $(_FLATRELEASEDIR)\test.lnk NK S
在project.dat中增加下面一行:
Directory("\Windows\startup"):-File("test.lnk","\Windows\test.lnk")
这样后系统启动后就会自动启动我们的程序了。
另外一种方法是编辑注册表:在project.reg中添加如下内容
[HKEY_LOCAL_MACHINE\init]
"Launch80"="app.exe"
"Depend80"=hex:14,00,1e,00
这个是设定启动顺序,launch后面的数字越大的越是后启动,Depend80后面的指定依赖项,为16进制,上面的语句表明依赖项为launch20定义的device.exe和launch30中定义的gwes.exe, 注意Launch后面的数字范围为0到99 ,此范围之外的将不会有效果。
这样两种方法的效果都是系统都是系统先启动资源管理器explorer.exe(就是看到的默认桌面),然后启动我们的程序,(如果利用taskman shell然后去掉任务栏那么效果更好)但是这样还不够,我们如何不显示桌面,直接显示我们的程序呢?
网上有人介绍的方法是去掉standard shell,但是我编译总是报错。我采用的方法是替换注册表中lauch50中的explorer.exe为我的app.exe,即搞定。
修改注册表的方法:先把带KITL的系统跑起来,在PB的TOOLS->Remote registry editor里修改,验证有效后,再去修改platfrom.reg, 或者自己写个REG文件,然后在platform.reg里INCLUDE进来 SYSGEN后确认PBWORKSPACE里相关项目的REL目录里reginit.ini文件里包含了自己做的修改后make image然后DOWNLOAD下去就OK了。
值得补充的是,我们前面介绍的步骤中那个修改平台setting,添加语句的,是因为我每次都是重新sysgen和build,如果只是简单的make image的话(都是pb中的build OS菜单下的命令),那么将直接用release中的内容,因此也可以直接将文件放到release文件夹,然后改project.bib等实现往image中添加文件。 同样,也可以直接修改release中的shell.reg中的launch50值为我们自己的程序(或者类似修改reginit.ini文件,reginit.ini文件存放有所有wince的静态注册表,来达到去掉桌面,直接启动我们程序的效果)。
注意,这么启动的程序,如果点击关闭,就会死机的,因为没有窗口运行了。实际运用中,当然不会让用户关闭我们的程序,除非他一起关闭系统。
如果也需要build的话,可以通过往image中添加文件的方法将我们改好的shell.reg添加到release目录