PE安装器说明by双心20200528

https://www.lanzous.com/b00n6291c 密码:6hih
https://share.weiyun.com/5749g5p
基于CxDirX86方案的模板文件8.5MB(不含PE.ISO)
请以管理员身份运行!请以管理员身份运行!请以管理员身份运行!
一、背景
    一直以来,大家都是利用PE来维护、安装系统,而PE多用grub4dos来引导,从引导介质来讲,主要有本地硬盘hd、优盘ud、光盘cd、PXE网络pd,启动PE的方式有解开启动和整体启动。而怎样快速简单地安装各种各样的PE到不同介质,手头一直没有合适的工具包,为了方便,我写了几个批处理,快速地在BIOS及UEFI启动的情况下安装PE到不同介质,主要实现以下目的:
1、快速部署,支持快速安装PE到本地硬盘、优盘、移动硬盘,支持从局域网部署到网内的任一台电脑。
★快速地安装PE到本地硬盘、普通优盘、固态优盘、移动硬盘的任何一个盘符,快速地在boot.ini或BCD中增加grub4dos的启动项。
★支持VHD、RAMOS启动的情况在原来的C盘添加grub4dos启动项,无论原来的C盘是否被分配了盘符,只要是活动分区的就可以。
★支持多硬盘的情况下修改主引导区的boot.ini或BCD。
★支持NT5.x下主引导是NTLDR单引导或者主引导是bootmgr转NTLDR的情况,BCD优先。
★支持unc网络路径,可以直接在网上邻居上的电脑运行,安装到本地任何一个可写盘符。
★除ud方式外,均为无损写入硬盘或优盘、移动硬盘的方式(不改变硬盘或优盘分区结构,不损坏原有数据)。
★只要你内存足够大,基本上任何一个PE都可以扔到ootimgs目录下,用该安装器安装到硬盘或优盘并启动,也可以pxe启动。
2、全自动编写菜单。
★无论是ISO、WIM、IMG格式,都能够全自动编写grub4dos/grub2整体启动菜单,wim格式的PE也能够自动加入到BCD菜单,从而减少书写错误的几率。
★菜单项采用了sed进行离线行编辑,自动根据选中的ISO镜像自动插入菜单项,如果你原来有菜单,也不会删除你原来的,只会增加非重复的启动项。
★插入菜单项时,如果grub4dos菜单已存在则删除里面已有的启动项后重建菜单,删除菜单启动项搜索的关键字是title+ISO镜像名称,一直删除到该行后的6行,所以整体启动ISO菜单要参考以后的菜单启动项模板编写,保证行数。UEFI如果采用grub2方案启动,ootgrub2grub.cfg菜单已存在则删除里面已有的启动项后重建菜单,删除菜单启动项搜索的关键字是menuentry+ISO镜像名称,一直删除到该行后的4行,所以整体启动ISO菜单要参考以后的菜单启动项模板编写,保证行数,一行可以用英文分号来顺序执行多条语句。
3、grub4dos的菜单文件menu.lst只有一个,适用于hd/ud/cd/ud等不同启动方式,具有通用性,“Write once,use everywhere”,如果要支持中文字库,menu.lst编码必须为utf-8格式。
4、BIOS启动时,把一个PE的光盘镜像ISO文件放到工具包内,不用改菜单就能够引导这个PE。利用的是sratlf的RUN模块,达到免写菜单的效果,不过启动时需要手工找到那个启动项。
5、结合tftpd32和tinypxeserver软件,能够作为服务器,用PXE网络启动局域网内的另一台电脑,不用改菜单,PXE启动免配置,双击里面的批处理即可启动PXE服务器。
6、集合常用的写引导工具bootice,UEFI引导工具grub2,ud制作工具fbinstool,sratlf的run模块。
7、在BIOS下可以制作UEFI启动盘,在UEFI下也可以制作BIOS启动盘,适用于多硬盘、优盘各种复杂模式启动,支持一键安装PE到空白硬盘,没有引导的一键添加引导。
★需要说明的是,很多新主板UEFI启动不但支持从GPT硬盘启动,还支持从MBR硬盘启动,甚至不需要FAT32分区,可以从MBR硬盘的NTFS分区启动。所以UEFI启动列举出了所有的分区,包括ESP/FAT32/NTFS分区供用户依据自己的引导分区情况自己选择,如果选择了EFIMicrosoftBootBCD不存在的分区,会自动补充UEFI所需的bootx64.efi、BCD引导文件。
★批处理会自动关闭前端进程输入法,按ALT+SHIFT(有的是CTRL+SHIFT)可以打开输入法。
 
二、软硬件适用条件
    支持BIOS/UEFI启动PE,支持XP WIN7 8 10版本的PE.ISO整体启动,支持解包后的PE.WIM启动。对于PE.ISO仿真到内存整体启动,大概要求物理内存比ISO体积大1GB左右。对于bootmgr作为第一启动的方案,系统自带的bcdedit命令要求能够正常运行不出错,因为需要这个自带的命令修改BCD的启动项,而且要以管理员身份运行。
   
三、不同引导方式下的具体用法
简单点来说,内存满足的前提下,把你喜欢的任何一个PE.ISO或者PE.WIM扔到imgs目录,运行批处理一路回车就行了,增加的第二个启动项是刚才安装的PE(第一个是windows)。 
http://wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=409019&pid=3889346&fromuid=298214
http://wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=409019&pid=3892134&fromuid=298214
http://wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=409019&pid=3895098&fromuid=298214
【01-PE安装器by双心】批处理(请以管理员身份运行):
1、BIOS启动菜单:
(1)ntldr/bootmgr==>grldr==>PE.ISO/PE.WIM,本地MBR硬盘和USB设备均可用(支持XP、WIN7/8/10,需要二次选择菜单)。
该方案能够在XP或者win7 8 10的引导菜单中增加grub4dos引导项目,电脑启动后按上下键就能选择grub4dos从而启动PE。多次运行不会增加重复启动项。
★当引导盘MBR为ntldr的时候,批处理会自动修改MBR/PBR为ntldr,引导流程为MBR→ntldr→boot.ini→grldr→pe.iso/wim。
★当引导盘MBR不是ntldr的时候,批处理会自动修改MBR为bootmgr,此时批处理会检测PBR是否为ntldr,如果是ntldr会提示修改为bootmgr(适用于MBR是bootmgr引导分区上的xp系统场景),引导pe.iso/wim流程为MBR→bootmgr→ootcd→grldr→pe.iso/wim。
(2)bootmgr==>PE.WIM,本地MBR硬盘和USB设备均可用(仅支持WIN7以上,一次选择菜单)。需要依赖boot.sdi,批处理已经拷贝到引导分区ootoot.sdi。
★用ver内部命令判断系统是不是xp/03,如果是WIN7以上系统,就修改引导盘的MBR/pbr为bootmgr,引导流程为MBR→bootmgr→ootcd→pe.wim。如果系统是xp/03,强行修改MBR为bootmgr的话会导致二次选单的情况,MBR→bootmgr→ootcd→ntldr→boot.ini→xp/03,没有必要,所以xp/03建议用上一个grldr中转的方案启动。
(3)grldr==>PE.ISO/PE.WIM,本地硬盘和USB设备均可用,USB设备推荐用该方式(一次选择菜单),格式化C盘也可启动其他盘的PE.ISO,会修改启动盘MBR为grub4dos。
★对于grub4dos作为第一引导器,ISO镜像存放在非系统盘的情况,可以格式化C盘,重做系统后,仍然可以进入PE,这种方案不用反复进入BIOS修改启动项设置,很方便可靠。
★该方案把grub4dos写入硬盘MBR,写入参数可以根据需要进行修改,当然也可以直接用Bootice的GUI。
★该方案同时在引导盘和ISO目标盘根目录menu.lst中以非重复方式离线插入启动项,避免启动时优先找到的是启动盘的menu.lst导致无法看到ISO目标盘里的启动项。
(4)修改启动盘MBR为windows ntldr/bootmgr
★如果引导盘存在bootmgr,就把MBR/PBR均修改为bootmgr,并自动修复引导所需的bootmgr、BCD引导文件;如果不存在bootmgr,但存在ntldr,就把MBR/PBR均修改为ntldr。
(5)一键添加bootmgr/bootmgfw.efi引导的BIOS/UEFI双启动PE.WIM (一般需要MBR硬盘上有一个FAT32激活分区,支持安全启动)
★注意:BIOS/UEFI双启动一般需要MBR分区表,一般要有个激活的FAT/ESP分区,但有的电脑不需要任何FAT/ESP分区也可以,不一而论。
(6)一键添加grub4dos/grub2x64.efi引导的BIOS/UEFI双启动PE.WIM/PE.ISO(一般需要MBR硬盘上有一个FAT32激活分区,需要关闭安全启动)
(7)切换到UEFI制作模式,用于制作UEFI启动盘,适用于多硬盘、优盘各种复杂模式启动,支持安装PE到空白硬盘。
(8)建立boot启动模板(不含ISO、wim、img镜像),可以在同盘根目录下建立一个boot_moban的文件夹,里面不包括PE.ISO。
 
2、UEFI启动菜单:
(1)bootmgr.efi==>PE.WIM,本地硬盘和USB设备均可用(一次选择菜单),需要依赖boot.sdi,批处理已经拷贝到引导分区ootoot.sdi。
(2)grub2x64.efi==>PE.ISO/PE.WIM,本地硬盘和USB设备均可用,USB设备推荐用该方式(一次选择菜单)。
(3)一键添加bootmgr/bootmgfw.efi引导的BIOS/UEFI双启动PE.WIM (一般需要MBR硬盘上有一个FAT32激活分区,支持安全启动)
★注意:BIOS/UEFI双启动一般需要MBR分区表,一般要有个激活的FAT/ESP分区,但有的电脑不需要任何FAT/ESP分区也可以,不一而论。
(4)一键添加grub4dos/grub2x64.efi引导的BIOS/UEFI双启动PE.WIM/PE.ISO(一般需要MBR硬盘上有一个FAT32激活分区,需要关闭安全启动)
(5)切换到BIOS制作模式,用于制作BIOS启动盘,适用于多硬盘、优盘各种复杂模式启动,支持安装PE到空白硬盘。
(6)建立boot启动模板(不含ISO、wim、img镜像),可以在同盘根目录下建立一个boot_moban的文件夹,里面不包括PE.ISO。
 
3、PXE启动:主机运行ootpxe目录下的任何一个批处理即可作为pxe服务器,在同一个局域网内的客户机BIOS开启PXE,启动到logo时按F12、F9、F8、F11或ESC这样的快捷键选择从pxe启动即可。
可选用tftpd32或者TinyPXEServer方案,随便扔个PE.ISO到ootimgs目录下,运行免配置批处理,就可以自动把该PE加入到ipxe/grub/grub2启动菜单。VM虚拟机测试,需要把虚拟机网络设置模式设置为自定义(U):特定虚拟网络VMnet0(自动桥接)。
由于tftp传输速度太慢,随着ipxe项目的发起,可以选用速度更快的http协议来进行网络启动,ootpxe目录提供了以下几种方案:
(1)03[BIOS][UEFI]TinyPXEServer免配置网启http服务器ipxe.pxe和ipxe.efi
BIOS下采用ipxe.pxe,UEFI下采用ipxe.efi,TinyPXEServer免配置,运行批处理可自动把pe.iso/wim加入到ipxe启动菜单ootipxemenu.ipxe中,客户机BIOS/UEFI-pxe自动适配。UEFI-PXE用的是sanboot方案。
(2)04[BIOS][UEFI]TinyPXEServer免配置网启http服务器undionly.kpxe和ipxe.efi
BIOS下采用undionly.kpxe,UEFI下采用ipxe.efi,TinyPXEServer免配置,运行批处理可自动把pe.iso/wim加入到ipxe启动菜单ootipxemenu.ipxe中,客户机BIOS/UEFI-pxe自动适配。UEFI-PXE用的是sanboot方案。
(3)05[BIOS]TinyPXEServer免配置网启http服务器启动ipxegrldr
采用chenall的ipxegrldr模块,从ipxe转到grldr启动,运行批处理可自动把pe.iso/wim加入到pxe启动菜单ootmenu.lst中,只支持BIOS-pxe启动。
(4)【06[BIOS]tftpd32免配置网启tftp服务器启动grldr】
批处理会自动设置好tftpd32起始IP,地址池大小,子网掩码,并可自动把pe.iso/wim加入到grub4dos启动菜单menu.lst中,只支持BIOS-pxe启动。
(5)【07[UEFI]TinyPXEServer免配置网启http服务器启动grub2x64.efi】
UEFI下采用grub2x64.efi,批处理会自动配置好TinyPXEServer,并可自动把pe.iso/wim加入到grub2启动菜单ootgrub2grub2pxe.cfg中,只支持UEFI-pxe启动。感觉grub2的http传输速度不快,不能跑满网速,而且grub2-pxe启动似乎和lang中文字体有冲突,所以PE不要用中文名字。另外TinyPXEServer的httpd似乎和grub2不能很好地适配,UEFI+TinyPXEServer(http)+grub2x64.efi+pe.iso可以启动,但是UEFI+TinyPXEServer(http)+grub2x64.efi+pe.wim组合就不行,用UEFI+TinyPXEServer(tftp)+EasyWebSvr(http)+grub2x64.efi+pe.wim组合就可以绕路解决(需要注意采用win7的bootmgfw.efi)。等待grub2的更新解决问题。
(6)【08[UEFI]TinyPXEServer免配置网启http服务器ipxe.efi-grub2x64.efi】
UEFI下采用ipxe.efi作为第一引导,进而引导grub2x64.efi,这样做的目的是可以让grub2的http传输达到满速,批处理会自动配置好TinyPXEServer,并可自动把pe.iso/wim加入到grub2启动菜单ootgrub2grub2pxe.cfg中,只支持UEFI-pxe启动,UEFI-grub2-pxe启动问题可以采取类似上面的方案绕路解决。grub2-pxe启动似乎和lang中文字体有冲突,现在用的loopback -m ramdisk (tftp)/grub2/unicode.xz到内存的办法,参见ootgrub2grub2pxe.cfg里面的内容。
温馨提示:
★tftpd32/haneWinDHCP+grub4dos方案只支持tftp协议,不支持http协议,不能跑满网速,不建议采用;建议采用TinyPXEServer+ipxe/grub2+webserver方案,支持tftp/http/ftp等传输协议,可以跑满网速,千兆网下速度较为理想。webserver可以采用王宝剑大神用VC++SDK编写的的绿色软件EasyWebSvr,只有惊人的67KB,配置简单。
★UEFI-ipxe-wimboot启动模式下BCD中默认文件名为boot.wim,boot.wim可以放在boot/imgs/下的任何一个子目录,批处理会遍历wim文件并加入到相应的启动菜单中;BIOS-ipxe-wimboot对于wim文件名字可以任意修改,但不建议使用特殊字符和中文。wimboot启动pe.wim需要涉及的文件太多,细节不注意很容易导致启动失败,我更喜欢用pe.iso启动方案。
★BIOS-pxe启动,如果想换个PE,除了用批处理自动写菜单的办法之外,还有个办法是用sratlf的run模块只需要把PE的ISO镜像文件拷贝到ootimgs目录下,运行【05生成ISO文件列表.bat】更新dir.txt(PXE启动需要),grub4dos菜单选择“run mem automenu by sratlf”就能从这个PE启动,run模块版本是20141206,实测与grldr20161224或者更早的版本匹配较好,可以遍历文件并启动,由于run模块已几年不更新,已经不能匹配最新版grub4dos,所以不推荐使用,推荐用批处理自动写菜单的办法。
4、USB启动方案:
(1)安装到优盘可见区,BOOTICE写入引导grub4dos或者wee,grldr==>PE.ISO,输入优盘所在盘符即可。
(2)安装到ud区:用fbinstool格式化优盘,把boot目录拖进ud根目录,再把grldr,menu.lst拷贝到ud根目录。
 
四、其他相关说明
1、注意:拷贝ISO过程中会挂载所有的隐藏分区,以保证能够正常拷贝grldr和menu.lst到启动分区,拷贝完成之后会自动卸载隐藏分区。因此拷贝文件时不要强行关闭批处理,否则隐藏分区不会被自动卸载。如果原目录已经有同名的ISO文件,则自动跳过,不会覆盖,节约时间。
2、关于启动盘的确定,提示用户选择,因为在PE下多硬盘的情况下无法准确判断启动分区,因此只能提示用户选择。
3、grub4dos启动的方案中,menu.lst菜单中有一项map --e820cycles=-1是参数默认值,如果整体仿真启动遇到蓝屏,在grub4dos启动主菜单按e键编辑,尝试改成1~4中的某个数值。
4、文件及目录结构
我个人比较喜欢uepon的通用PE和微PE,菜单以微PE整体启动为例。这里以实用为主,没有考虑背景图片。
软件包的目录结构:
X:
  │  grldr
  │  menu.lst
  ├─BOOT(Legacy BIOS启动用)
  │   ├─BOOTICE(存放bootice工具)
  │   ├─FbinstTool(存放FbinstTool工具)
  │   ├─imgs(存放PE的ISO镜像文件,各种软件img镜像文件)
  │   ├─grub(内有grldr.*、menu.lst的备份,批处理会自动把备份拷贝到根目录,还存放font字库、sratlf的run模块和网启服务器tftpd32.*)
  │   └─grub2(存放grub2x64.efi、grub.cfg、unicode.pf2、zh_CN.mo等) 
  │   └─pxe(存放pxe启动免配置批处理及引导器相关文件,可把pe.iso/wim加入到ipxe/grub2/grub4dos启动菜单中) 
   个人觉得,安装系统最最稳妥的方式是从硬盘启动PE来安装,优盘、PXE启动毕竟没有本地硬盘启动方便,还要进BIOS改启动顺序,只要硬盘能够进入Windows,就在Windows下运行那个批处理,把PE安装到除C盘之外的任何一个盘符,直接用批处理一键把硬盘MBR修改为grub4dos,这样随心所欲地安装系统,格式化C盘也没事,PE仍然能从非系统盘启动,安装完毕如果喜欢ntldr或者bootmgr的引导方式,也可以改回来。如果手头没有优盘,没有第二台电脑,网上下载这个工具包,安装到非系统盘是最稳妥的办法了。你甚至可以保存在手机中,在半死的Windows中部署到硬盘。
 
五、用到的命令或工具
1、DetectEFI32,50KB,adef提供,我重新编译,检测当前系统是BIOS启动还是UEFI启动。
http://bbs.wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=413675&pid=3792649&fromuid=298214
判断当前系统是BIOS启动还是UEFI启动,分区表是MBR还是GPT(by双心)V1.3 http://wuyou.net/forum.php?mod=viewthread&tid=412368 (文件稍大已放弃)
2、grub4dos-0.4.6a-2016-12-24,310KB,该版本与sratlf版主的RUN20141206版本兼容性较好,较新版本的grub4dos可能与sratlf的RUN模块不兼容,因此不推荐更换为最新版本的grub4dos,除非你不用RUN模块,或者当前版本的grub4dos在你的电脑上根本无法启动。
3、sratlf的RUN20141206模块,746KB,RUN 1206 更新 支持磁盘交换,文件检索,自动菜单,自动列表,全自动安装nt5x系统
 http://bbs.wuyou.net/forum.php?mod=viewthread&tid=191301
4、booticeX861.3.4,451KB,pauly的写引导工具。http://wuyou.net/forum.php?mod=viewthread&tid=57675&extra=page%3D1
   XorbootUEFI0.2.5,3.88MB,pauly的UEFI引导工具(暂不支持命令行,改用grub2)。http://wuyou.net/forum.php?mod=viewthread&tid=157812&extra=page%3D1
5、grubinst1.4,151kb,freesoft00分享,用于写入grub4dos引导,bootice命令行写入MBR有bug,会导致“优先尝试引导原来的MBR”选项被选中,对于一个空白的新硬盘或者优盘,当PBR是ntldr/bootmgr,而盘上不存在ntldr/bootmgr这一套引导文件的时候,“优先尝试引导原来的MBR”这个选项会导致空白的新硬盘或者优盘无法引导。因此放弃bootice写入方案,改用grubinst1.4命令行写入方案。http://bbs.wuyou.net/forum.php?mod=viewthread&tid=355942
6、CxDirX86,23.5KB,2012jiashanni分享,用于显示磁盘分区相关信息,例如磁盘大小、卷标、MBR/GPT、文件分区、活动分区,可能是某网友基于drvtype思想写的,来源不明,总之是大神写的。当初也曾考虑过采用diskpart方案,diskpart限制太多,涉及到windows不同版本需要做很多测试,而且需要用到很多批处理技巧,因此放弃diskpart,直接采用现成的CxDirX86。
http://bbs.wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=414335&pid=3789135&fromuid=298214
7、sed for windows,233KB,为批处理插上了飞翔的翅膀,是批处理的灵魂。https://github.com/mbuilov/sed-windows
8、encodeconv.exe,162KB,游蓝海原创,liuzhaoyzz改进后可自动识别原文件编码,静态编译不需要运行库支持。https://www.cnblogs.com/liuzhaoyzz/p/11392294.html
concmd,261KB,tmplinshi版主提供,用于gbk,utf8编码转换。http://www.bathome.net/thread-12595-1-1.html(已放弃,因为需要语言包支撑)
9、find,15.5KB,windows系统自带的。不同系统命令不一定通用,因为windows的小程序都有文件签名,所以未放到文件包里。
10、mountvol,14.5KB,windows系统自带的。不同系统命令不一定通用,因为windows的小程序都有文件签名,所以未放到文件包里。
11、bcdeditX86,320KB,提取自win8X86,可以解决部分WIN7系统bcdedit无法运行的问题,要求当前系统盘必须激活。
12、bootsect.exe,108KB,提取自微软光盘,用于修改MBR/pbr为ntldr/bootmgr。
13、PXE启动可选用tftpd32/196KB或者ljycslg分享的TinyPXEServer/928KB方案,用里面的批处理可以免配置。
Tiny PXE Server 1.0.0.20 汉化版http://bbs.wuyou.net/forum.php?mod=viewthread&tid=375813
14、FbinstTool1.701.2017.0318,1.74MB,由jianliulin编写,内置了bean编写的fbinst,是用于增强usb启动成功率的工具。
http://bbs.wuyou.net/forum.php?mod=viewthread&tid=189221
15、[测试]GRUB2 UEFI 下的磁盘仿真 20191105更新 - GRUB2 - 无忧启动论坛 - http://wuyou.net/forum.php?mod=viewthread&tid=417233&extra=page%3D1
https://github.com/a1ive/grub
采用wintoflash大神修改的grub2,支持UEFI下map --mem PE.ISO,为了保持目录结构清晰,因此69楼用grub-mkimage -c bootconfig.cfg命令进行了定制修改,默认查找ootgrub2grub.cfg。
还采用了wintoflash的grub2-filemanager模块用于遍历pe.wim文件并启动,参考了hilsonma给出的菜单。https://github.com/a1ive/grub2-filemanager
16、采用我编写的40KB的closeinput来关闭输入法,防止盘符输入干扰。
17、感谢5大提供的ChkMbrPbr检测MBR/PBR是NT5/NT6:http://wuyou.net/forum.php?mod=viewthread&tid=420355&extra=
 
六、待完善的地方:
1、grub4dos启动画面没有用图片,不够精美,没有用采用中文菜单,因为一闪而过。注意如果采用中文,menu.lst必须采用utf-8编码。
2、用的批处理连接各个exe小程序,不如直接用au3、VBVC、delphi这样的工具写出来的高大上,界面不够美观。有利有弊吧,批处理的好处是开源、接地气,大家都可以根据自己的情况更改代码,以适应自己的需求。
 
七、特别鸣谢
不点、bean、chenall、2011yaya2007777(grub4dos开发者们)、pauly(bootice、XorbootUEFI作者)、jianliulin(FbinstTool)、adef(DetectEFI)、CxDir(2012jiashanni)、sratlf(RUN模块作者)、歌理(PXE免配菜单)、ljycslg(tinypxeserver汉化分享)、芈员外(一键RAMOS框架)、tmplinshi(concmd作者)、freesoft00(grubist1.4分享)、wintoflash(UEFI-grub2_map、ntboot)、hilsonma、极限驱动、2011hiboy(Grub2定制UEFI模板)、captain_g(IPXE-UEFI网启小工具)、yigeren(TinyPXEServer自动识别BIOS/UEFI的配置文件)、江南一根葱、jie_china(grub2-pxe文章推送)、527104427(5大提供了ChkMbrPbr检测MBR/PBR)、2011泥土清香(问题反馈)...等等等等。
原文地址:https://www.cnblogs.com/liuzhaoyzz/p/4204262.html