[分享] 《步步为营封 Win7》--skyfree
Skyfree 发表于 2009-9-13 05:51:32
https://www.itsk.com/thread-20957-1-25.html
[分享] [0]《步步为营封 Win7》引言
《步步为营封 Win7》引言
WIN7 RTM发布已经有好几天了,其实我从最早VISTA时就研究过WIN6.X这一代系统的封装,之前又在WIN7 7264版本上实践过部分WIN7封装技术。想了很久,不想像以前那样只发个傻瓜化的工具给大家用,因为那样会使很多技术变得封锁起来,所以我决定写这篇教程。
这篇教程可能会分成很多章节,我会每隔1~3天更新一章,在这期间我会和大家一起一步步的完成对WIN7的封装,并和大家共同探讨这其中的问题,很渴望大家能积极参与。今天我只写了个引言,也算是我的一些感慨,不过我仍请大家细读一下这个引言,这将为我们今后一起研究WIN7封装打下良好的基础。
(品行不良的、想来拿了东西就走的、想剽窃其他人劳动成果的,勿看本文)
引言
虽然是引言,但是我仍请大家耐下心来阅读,我相信本文即使是引言部分也可以给您带来些许收获。
(一)现状!
傻瓜式工具最终造就了什么?本来制作各类智能化工具的初衷是提高工作效率、降低技术门槛以及减少不必要的人力物力消耗,但从实际情况看,并非是如此。
工具越来越智能,操作的选项越来越少,很多以前需要大量手工操作的事情现在变得按一下按钮一切搞定。诚然,这提高了工作效率,但也一定程度上的封锁了技术,降低了真正技术的交流。试问有多少人了解这一个按钮后面的真正技术?有多少人真的明白智能化工具究竟做了哪些事情?越来越少的人关心封装部署技术的核心部分,越来越多的人只追求封个系统了事,太多人习惯于浮于表面的所谓技术交流,太多人习惯于等待高手做出“按一个按钮解决一切事情”的工具。
如果有太多人依赖智能化工具,那将有太多人不明白这项技术的真谛,那会导致只有太少的人能进行这方面的技术交流。技术交流渠道越来越窄,技术水平发展速度越来越慢,技术层次越来越低,这样的结果又有几个人希望看到?本文立足于这个现状,借微软Windows7操作系统的发布,和大家一同探讨系统封装与部署技术。当然,由于Windows7是最新的操作系统,本文又写于Windows7刚刚发布之际,如文中有各种差错,还请大家谅解。
本文的最终目的,旨在让人人都能真正理解这项技术,从而逐步构造一个技术交流的氛围,最终打破现在“等工具,封装,等工具,封装”的现状,共同构筑大家的技术共享平台。
(二)封闭?
天空的最初原则就是开源,“技术开源传万世,共同革新同提高”是自由天空最初的口号,同样是最终的目的。但同样,我也不只一次的听别人说我们天空变质了,变得不乐于开放技术了,是吗?开源是什么,这里不多说,有兴趣多问问百度和谷歌。但我要强调的是,开源绝不是某些人认为的“开源就是可以随便拿走,稍加修改就可以说是我自己原创”!
天空写出的教程,被不良居心的人拿走,改改作者名即说教程中的滴滴汗水都是他们原创;天空研究的代码,被无德无知的人拿走,改几个变量名就说代码中的种种心血都是他们原创;天空整理的驱动,被无能无术的人拿走,复制粘贴一下就说那大量的时间和精力都是他们的原创!当这些人被追问时,他们经常反咬一口,“你们不就是开源吗?”、“开源不就是可以随便拿走吗?”、“网络不就是这样吗?”。诚心的请问你们真的懂什么是开源吗?试问各位天空论坛的老坛友,大家记得天空从创建到今天各种剽窃事件发生了多少起?而这次次事件又让天空寒透了多少回的心啊!
由于这些无德之辈的存在,我们无法全心全意的开放与交流技术,他们实在令我们每一个开源者无法敞开心扉和大家交流。最终是谁封闭了技术?大家心领神会吧。
(三)概念……
如果基本概念搞不清楚,那么技术就会有倾斜;如果太多的基础概念搞不清楚,成就的技术绝不能称为技术。没有哪个数学家不懂一元一次方程的,没有哪个物理学家搞不清楚牛顿定律的,系统封装与部署也是一样。
1、什么是系统封装
我不想用官样的语言来描述这个概念,想必没人想看微软式的帮助——你读得懂每个字,就是看不明白说的什么意思。那么我就用最普通的方法来描述这个概念:
系统封装就是将系统打回到“准备状态”,从而可以部署至更多的计算机。
我们可以将A计算机中已经安装好了的Windows7进行封装操作,从而A计算机中Windows7重新进入了“准备状态”。而后通过微软官方映像工具(ImageX等)或者第三方映像工具(Ghost等)对A计算机中的Windows7进行备份,而后再通过这类工具将Windows7处于“准备状态”的映像恢复到B计算机中。而后Windows7在B计算机中开始执行部署过程。
A计算机中安装好的Windows7→封装→“准备状态”的Windows7→备份到→Windows7映像→恢复到→B计算机→B计算机中的Windows7开始部署→B计算机中安装好的Windows7。
系统封装是一种快速的将一台计算机中的操作系统快速的部署于多台计算机的技术,系统封装和部署过程中,很多系统设置会还原到最初值,所以部署到其他计算机中的系统可以一定程度上认为是全新的系统——当然,某些设置、软件的安装、补丁的安装、系统优化等还是保留的。
2、封装部署不是克隆
或许是使用到了Ghost,或许是早年部分人图方便直接使用了Ghost对系统进行克隆,让系统封装与部署莫名的背上了“克隆版”的黑锅,同样也被扣上了各种“不稳定”、“不如安装版”的不明不白的怀疑。
上文已述,Ghost只是一个映像工具,负责的仅仅是“将封装好的系统进行备份为系统映像”和“将系统映像恢复到其他计算机”这么一个工作,Ghost本身并未参与系统封装和部署的任何一个过程。如果你喜欢,还可以用ImageX、ATI等映像创建与恢复工具,不一定要用Ghost。所以,“克隆版”只是很多不明技术真相的人的一个很不专业的通称而已。至于封装部署的系统是否没有安装版稳定,个人感觉不是个需要讨论的问题。系统安装技术来自于微软本身,而系统封装与部署技术也来自于微软本身,自家兄弟的强弱与否貌似毫无争论的必要。
由于曾经存在过的各类改版系统采用了系统封装与部署技术,很多这种改版的制作者又对系统进行了各种精简优化操作、使用了不成熟的磁盘控制器驱动技术等,从而总是让封装部署版的系统带有相对“不稳定”的特性。这种不稳定完全由改版制作者的技术决定,与封装部署技术本身的稳定性毫无关系。
3、封装部署不是盗版
前文已经多次提到,系统封装与部署技术就是微软自家的技术,目的是提高系统安装速度、降低IT专业人士重复的机械操作。由于这项技术的这种优势和特性,使得很多计算机销售商乐于使用这种技术,毕竟不可能总是重复为每一台计算机安装系统、打补丁、装软件等机械过程,这会带来不必要的人力物力损失。
由于国内大部分人对操作系统版权意识的淡薄,而正版Windows操作系统的价格又居高不下,导致了不少人动了歪念头。例如经典的使用XP大客户版制成封装部署版,以盗版光碟或网络传播的方式散布盗版系统。盗版系统的制作者采用的正式封装与部署技术,因为这种技术最为方便,技术门槛也最低。正是这个原因,让很多人一想到系统封装与部署技术,立刻就联想到了盗版。但这是不公平的,也是没有任何理由的。
系统封装与部署技术是一项技术,这是一项可以方便你我他的技术。而有些人将这项技术用于了不正的途径,就像有人拿菜刀砍伤了人一样,砍伤人完全是行为人负责,难道与菜刀有关吗?
4、封装工具是什么
既然系统封装工具是微软的,那么我们现在常见的各种“封装工具”又是什么?
准确的说,现在网络间流传的“封装工具”绝大多数都是“系统封装辅助工具”。这些工具本身并不具有对系统进行封装和使系统进行部署的能力,系统封装和部署仍旧是依靠微软官方的工具。“系统封装辅助工具”的主要职责,是将平时需要手动配置的各种项目图形化和智能化、扩展系统部署的范围与适用性等。
这也就是说,“系统封装辅助工具”是辅助我们进行各种操作、扩展系统封装部署性能的工具,它们在执行过程中会调用微软官方工具执行具体项目。
(四)技术——
我们要一起研究这项技术,Windows7是一个不错的开始,因为在Windows7面前我们都是一样的,我们又有了一个新的起点,我们都站在了相同的起跑线上。
研究技术最忌讳的事情:
1、掺入自己主观观念的技术。不要给自己的技术加入任何主观观念,要客观的看待任何问题,对任何技术的理解必须有理有据,不可主观臆断。
2、感觉自己很NB。半瓶子醋总是逛荡的,反倒是满瓶醋逛荡不起来。肚子里稍微有点东西请勿感觉自己牛,可知山外有山、人为有人,况且任何人但凡有一点比你强就是你的老师!
3、嘲笑新手。这反映了两个问题,第一,你绝不是高手;第二,心态浮躁。
4、过大的询问某个问题。提问时一定要细化问题,不能猛一下提个很“宽广”的问题。例如“谁来教我封装?”、“怎么自动封装?”、“SRS驱动怎么做?”等。这种貌似只有一句话很简单的问题,其中包含的小问题数绝对都在三位数以上。如果你这样提问,没有人回答你是很正常的,无需抱怨。
研究技术,一定要踏踏实实稳稳当当,切忌浮躁。提问前一定要自己先研究,没有失败经历的人绝不可能做成技术。而如果你要提问,则问题越是细化越是可以更快得到答案。
从来就没有高手,只要用心,人人都是高手!
欢迎大家共同交流技术,努力打造最优秀的技术社区!
[分享] [1]《步步为营封 Win7》基础
Skyfree 发表于 2009-9-13 05:17:41
https://www.itsk.com/thread-20953-1-25.html
一、《步步为营封 Win7》基础
一切都得从基础开始,只有懂得和掌握了最最基础的东西,才有可能撑起更多的上层技术。所以我们有必要了解用最基本的方法如何封装Windows7,从基本逐步延伸到高层。
(如下内容以Windows 7 RTM x86 简体中文旗舰版为例)
(一)Windows7的安装
这里我不想长篇累牍的讲述如何如何安装Windows7,在此讨论系统封装部署的各位想必都会安装Windows7,在这里我想说几点在Windows7安装中需要注意的地方。
如果我们的硬盘是尚未使用的,如下图:
<ignore_js_op>
在尚未使用的硬盘上安装Windows7,分区时会有一些有趣的事情,如下图:
<ignore_js_op>
1、从Windows Vista开始的Win6.x这代系统(Windows7版本号为Windows6.1,其实和Vista一样属于Win6.x),在执行分区操作时只能创建主分区(如果是我个人技术问题请指正),我不明白为什么微软要这样设定。锁定只能格式化为NTFS如果尚可理解的话,只能创建主分区又是什么目的?
2、如果硬盘是尚未使用的,为Windows7创建分区时会自动创建一个100M的所谓“系统分区”,而Windows Vista SP2和Windows Server 2008 SP2都没有这种现象。这个分区默认是隐藏的,即Windows7安装好后是看不到的。经过仔细对比后发现这个100M的分区里盛放的是Windows7的一些启动相关文件(有兴趣进PE查看)。
我们暂且把这个100M的分区叫做“启动区”,安装系统的分区叫做“系统区”。一开始我感觉很新奇,后来回想一下XP时代其实微软就已经这样做了,只不过那时候没有现在完善而且不强制罢了。有兴趣的朋友可以试试,在未安装系统的硬盘上安装XP时分一个100M左右的C盘,然后把系统安装到D盘去,XP也会复制它的启动文件到C盘,而把系统文件装在D盘,这和Windows7的这种强制做法一致。
从XP到VISTA,包含启动文件的启动区和包含系统文件的系统区同在C盘,而Windows7则是单独划出一个100M的分区当做启动区以盛放启动文件,又将系统文件放置于其他分区。看到这里也发现没什么特别出奇的,只不过是分开放置了一下文件而已,就像Linux把/boot挂载到一个单独的分区一样。
到这里大多数朋友都看出来了,第一,这个100M的分区的实际意义并不是特别强大,而且由来已久,不是Windows7特有的;第二,这种把启动区独立出来的方法不方便封装后系统映像的备份与转移工作。既然如此,那么我们就自己划定分区吧,即不用莫名多个100M的分区,也不用为不能划分逻辑分区发愁。
使用其他硬盘分区工具操作(注意,强烈不推荐PQ和PM),分区后重新进入系统安装过程,如下图:
<ignore_js_op>
看到这个界面猛的熟悉了很多,这是我们最常见的分区模式,那就继续执行我们的系统安装操作吧!
<ignore_js_op>
稍等片刻后,系统安装完毕,如下图:
<ignore_js_op>
Windows7安装好后,会启动一个OOBE过程,在这个过程里要输入各项系统设定。这里会强制用户输入一个全新的用户名,并根据这个用户名确定计算机名。Windows7默认是不允许使用Administrator进行登录的,而是使用刚才我们创建的那个用户。但实践证明,系统封装强烈推荐使用Administrator账户(原因后述)。
下面我们开启并使用Administrator账户,进入计算机管理界面:
<ignore_js_op>
打开Administrator账户的属性,将“账户已禁用”前面的对号去掉:
<ignore_js_op>
而后删除掉刚才创建的用户账户,如“SkyUN”:
<ignore_js_op>
这时会有一些提示,建议看一看,然后一路确定下去。用户账户调整完毕后如下图:
<ignore_js_op>
即计算机内只有Administrator和Guest两个账户,Admnistrator账户为启用状态。而后注销当前用户,注销后看到如下图界面:
<ignore_js_op>
选择Administrator登陆系统,进入用户桌面后,对系统简单调整后如下图:
<ignore_js_op>
到这里,我们就以系统封装为目的完成了对Windows7的安装操作,建议使用Ghost备份一下当前的系统,以备以后再次使用。
(二)Windows7的封装与部署
现在我们使用微软官方的系统封装工具执行一次封装,让大家看看最原始的封装方式是什么样子的。
Win5.x(2000/XP/2003)的系统封装工具都位于他们的系统光盘上,而Win6.x的系统封装工具都位于系统分区内。打开C:\Windows\System32\Sysprep文件夹,你就会看到Sysprep3.14版。
运行sysprep.exe,“系统清理操作”选择“进入系统全新体验(OOBE)”,选中“通用”;“关机选项”选择“退出”——如果您想直接重启或关机也可以选择对应选项,选退出是为了方便观察。
<ignore_js_op>
选项设定结束后,单击“确定”按钮,执行系统封装。sysprep3.14执行系统封装分为两步:
<ignore_js_op>
<ignore_js_op>
务必在封装时观察是否执行了这两步,sysprep3.14在Windows7下有一定的失败率(高于在Vista下的失败率),而且失败的原因莫名其妙,有时因为调整一下页面文件都会造成封装失败,很无语。
如果顺利执行完了这两个封装步骤,会看到Sysprep文件夹下生成一个封装成功的TAG文件:
<ignore_js_op>
其实到这里Win7的基本封装就结束了,重新启动计算机,我们看一下Windows7的部署过程:
1、更新注册表设置
<ignore_js_op>
2、启动基本服务
<ignore_js_op>
3、安装设备驱动
<ignore_js_op>
4、应用系统设置
<ignore_js_op>
5、基本部署结束,重启计算机
<ignore_js_op>
6、又进入了熟悉的OOBE,新建账户
<ignore_js_op>
7、使用账户登录进入桌面
<ignore_js_op>
这样,整个系统封装并部署的过程就完成了。大家可以发现原始的封装部署是一件十分简单的过程,而且操作并不复杂。
(三)基本封装部署问与答
1、为什么建议使用Administrator账户进行封装?
(1)如果我们使用普通账户进行封装,封装完毕部署后仍然会进入OOBE过程,仍然会要求我们新建一个账户,而且这个账户是不可以与我们之前封装所用的账户冲突的,这无疑形成了一种残留,或者说是冲突。
(2)普通账户下,虽然用鼠标双击某些程序可以直接运行,但使用自动化程序调用某些程序、在C盘下建立目录等操作时会有问题,有兴趣可以尝试一下,这对我们下一步的自动化封装部署形成了障碍。
(3)我们删除安装时创建的账户,而是用Administrator账户进行封装操作,这在程序执行上有很多便利。而且Windows7在封装部署后又会自动禁用Administrator账户,就像我们第一次安装系统时那样,在部署后的OOBE时再创建任何账户都不会与当前系统内的账户冲突,就像全新安装系统那样,很是干净。
2、Windows7封装还是否需要卸载驱动?
我没有在官方找到相关说明,但根据实际经验来看是需要的。至于为什么我没有在这次演示中卸载驱动,是为了给大家原汁原味的展示微软官方封装部署是个什么样子。
3、Windows7封装部署是否还需要额外的磁盘控制器驱动?
这个我可以很确定的说需要。很多偏颇的认识过于神话Windows7,几乎把Windows7吹成无所不能的,但实际绝非如此。
诚然,Windows7集成了一定量的常用磁盘控制器驱动,可以暂时应付常见机型,但并不代表着Windows7不需要增补磁盘控制器驱动,更不代表着今后不需要添加磁盘控制器驱动!就像2001年时的XP,当时XP的自带驱动也几乎是无敌的,而在8年后的今天,没有额外磁盘控制器驱动的XP几乎是寸步难行的。
所以,磁盘控制器驱动的增补是必须的。
4、Windows7封装部署是否还需要针对硬件抽象层进行修改?
首先我们来了解一下什么是硬件抽象层(HAL),我们可以把HAL认为是一组类,虽然我们的计算机硬件配置千差万别,但都可以归为HAL中的一个类,例如XP时代单核心的计算机归为一类、多核心计算机归为一类等。
但到了Windows7(其实从Vista开始就已是如此),HAL被简化为只有两类,即x86的HAL和x64的HAL。所以我们无需再担心HAL的问题,我们只需要知道我们封装的是x86还是x64的系统就可以了。
关于Windows7的基本封装与部署就介绍到此,希望能给大家带来帮助和启发。篮球天才也得每天练习最基本的运球和投篮,记住这句话。
感谢大家的支持!请单击 http://www.2345.com/?751 为天空带来收益!
[分享] [2]《步步为营封 Win7》驱动处理
Skyfree 发表于 2009-9-13 05:32:20
https://www.itsk.com/thread-20955-1-25.html
二、驱动处理
(一)简介
封装前都会对封装用计算机(源计算机)中的硬件设备驱动进行处理。所谓处理,主要是卸载驱动,以及一些对驱动程序的调整等。
为什么要卸载源计算机的硬件设备驱动程序?理论上说,卸载源计算机的驱动不是必要的步骤,Windows本身就具有对硬件的即插即用能力,例如你添加一块网卡、更换一块显卡系统都会自动帮你搜寻适合的驱动并尝试安装。系统封装与部署技术是将源计算机中的系统封装后部署到其他计算机上,对系统来说并不认为是系统部署到了不同计算机中,而是发现了更多的即插即用设备,系统会为这些“多出来”的设备自动搜索与安装驱动。
但是事与愿违,只有实践才能检验理论。在实际的系统封装与部署中,由于硬件不卸载带来的一系列的小问题层出不穷。这些问题中有些的确是由于硬件商造成的,例如XP时代经典的声卡ID冲突问题;而也有一些也是由于Windows本身的功能造成的,例如出现“本地连接2”等。再加之每个用户都不想要一个“不干净”的系统,所以驱动处理逐渐的成为了必须要做的事情。
(二)原理
<ignore_js_op>
处理驱动程序不是什么难事,估计没有人不会卸载驱动与更改驱动。所以,在本文里我绝对不会和大家探讨怎么一步步的在设备管理器里点鼠标卸载驱动,这无异于浪费大家的时间和精力。我们要讨论的是怎么自动的卸载这些驱动程序,毕竟大家都喜欢双击一个程序解决一切问题的舒适感。今天我们要做的,就是要了解这种舒适感背后的技术。
每种硬件都有它们自己的ID,要查看硬件的ID很容易,如下图:
<ignore_js_op>
从图中可以看到,硬件不只有一个ID,一般来说一个硬件的硬件ID(HWID)会有1~4个。HWID就像身份证号一样独立标识着每类硬件,所以我们很容易的可以想到会存在一组硬件与HWID的对应关系列表。如何获得这个列表?打开注册表:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum
可以看到其下的分类,打开某一个分类,例如Display,再选取下面的硬件子类,例如我计算机中的:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\DISPLAY\BNQ76D9
打开后会发现其下有以设备编号命名的设备键,例如我计算机中的:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\DISPLAY\BNQ76D9\5&5db3def&0&UID268435459
这其实是我的BENQ显示器,显示器的标识是“5&5db3def&0&UID268435459”,我们来看一下“5&5db3def&0&UID268435459”下的子键,找到“HardwareID”键,它的键值即是我的BENQ显示器的HWID。
当然您的显示器不可能完全与我的一样,但您可以在类似的位置找到您显示器的HWID。如果您已经找到了,那么可以以此类推看看其他硬件的HWID。您会发现HardwareID键包括多个HWID键值,就像我们在设备管理器里看到的一样。这也就是说,我们可以通过注册表来获取本机所有硬件设备的HWID列表了!
说到这里您大概会有如下两个问题了:
1、我们有了HWID又能做什么?有HWID就能自动卸载驱动吗?
2、怎么获取这个列表,难道要我们手工一个个的复制粘贴吗?
下面我们来逐步解决这些问题,我们要用到命令行工具的操作基础和一定的AU3基础,如果您这两方面比较薄弱,那么建议先多学习一下这方面的知识再来学习如下内容。
(三)DevCon.exe
DevCon.exe是微软的可代替设备管理器的命令行工具。虽然是个命令行工具,但实际上讲,它有着比设备管理器更强大的性能。如果对此工具有更多兴趣,可以查阅微软官方支持:http://support.microsoft.com/kb/311272/zh-cn。
DevCon.exe的说明(读取自微软):
devcon.exe [-r] [-m:\\<machine>] <command> [<arg>...]
-r 如果指定它,在命令完成后若需要则重新启动计算机。
<machine> 是目标计算机的名称。
<command> 是将要执行的命令(如下所示)。
<arg>... 是命令需要的一个或多个参数。
要获取关于某一特定命令的帮助,请键入:devcon.exe help <command>
classfilter,允许修改类别筛选程序。
classes,列出所有设备安装类别。
disable,禁用与指定的硬件或实例 ID 匹配的设备。
driverfiles,列出针对设备安装的驱动程序文件。
drivernodes,列出设备的所有驱动程序节点。
enable,启用与指定的硬件或实例 ID 匹配的设备。
find,查找与指定的硬件或实例 ID 匹配的设备。
findall,查找设备,包括那些未显示的设备。
help,显示此信息。
hwids,列出设备的硬件 ID。
install,手动安装设备。
listclass,列出某一安装类别的所有设备。
reboot,重新启动本地计算机。
remove,删除与特定的硬件或实例 ID 匹配的设备。
rescan,扫描以发现新的硬件。
resources,列出设备的硬件资源。
restart,重新启动与特定的硬件或实例 ID 匹配的设备。
stack,列出预期的设备驱动程序堆栈。
status,列出设备的运行状态。
update,手动更新设备。
UpdateNI,手动更新设备,无用户提示
SetHwID,添加、删除和更改根枚举设备的硬件 ID 的顺序。
这的确是一个功能很多的工具,但今天我们只需要它的一个功能就可以了,毕竟我们只需要用DevCon.exe来卸载驱动。我们来看DevCon.exe的“remove”功能,此功能的语法是:
DevCon.exe remove [HWID]
DevCon.exe的这个功能的主要目的,是移除使用本HWID的硬件驱动程序。即,我们只要知道设备的HWID,就可以通过DevCon.exe的命令行模式将其卸载。例如我们要卸载一个HWID为“PCI\VEN_1002&DEV_4393&CC_0104”设备的驱动,则:
DevCon.exe remove PCI\VEN_1002&DEV_4393&CC_0104
这为我们自动卸载驱动做了最好的铺垫。
(四)自动卸载
1、自动获取HWID列表
既然我们只要有硬件的HWID就能卸载该硬件的驱动,那么我们现在就要想办法怎么弄到计算机中所有硬件的HWID列表了。前文已述,可以通过读取注册表的方法获取HWID,那么我们就可以通过AU3实现。
Func _DrvUnins_ReadHwids()
Local $HwidList[1][2], $p = 1
Local $RootKey = "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum"
Local $i = 1
While 1
Local $SubKey1 = RegEnumKey($RootKey, $i)
If @error = -1 Then ExitLoop
$SubKey1 = $RootKey & "\" & $SubKey1
Local $j = 1
While 1
Local $SubKey2 = RegEnumKey($SubKey1, $j)
If @error = -1 Then ExitLoop
$SubKey2 = $SubKey1 & "\" & $SubKey2
Local $k = 1
While 1
Local $SubKey3 = RegEnumKey($SubKey2, $k)
If @error = -1 Then ExitLoop
$SubKey3 = $SubKey2 & "\" & $SubKey3
Local $Cls = RegRead($SubKey3, "Class")
;
If $Cls <> "Mouse" And _
$Cls <> "Keyboard" And _
$Cls <> "System" And _
$Cls <> "LegacyDriver" And _
$Cls <> "Computer" And _
$Cls <> "" Then
ReDim $HwidList[$p + 1][2]
$HwidList[$p][0] = $SubKey3
$HwidList[$p][1] = RegRead($SubKey3, "HardwareID")
$p += 1
EndIf
$k += 1
WEnd
$j += 1
WEnd
$i += 1
WEnd
Return $HwidList
EndFunc ;==>_DrvUnins_ReadHwids
函数_DrvUnins_ReadHwids的目的,即是列举本机HWID列表。我做一下简单的说明:
(1)本函数中通过三层循环,依次读取Enum键下的设备类、设备子类、设备信息,最终获取每个设备的HWID;
(2)本函数最初创建一个$HwidList数组,随着读取工作的进行而逐步扩大数据量,$HwidList数组中保存的即为本机HWID列表;
(3)在决定要读取某个设备的HWID之前,还要判定一下该设备属于哪类设备,通过读取设备信息键值下的Class键值实现;
(4)在Windows7下有5类设备没必要卸载,分别是PS2鼠标(Mouse)、PS2键盘(Keyboard)、系统设备(System)、系统遗留驱动(LegacyDriver)、硬件抽象层(HAL、或称计算机类型、或俗称电源管理)(Computer),所以只要设备属于这5类则不加入硬件ID列表。
(5)本函数的返回值为一个数组,数组内容即为本机HWID列表。
2、整理HWID列表
同类硬件有相同的HWID,例如两个相同的网卡,例如一个CPU的多个核心。HWID是定位到硬件类,而不是像网卡的MAC地址一样定位到每一个硬件,所以我们获得的HWID列表中很大可能性的存在相同的HWID。
虽然这些相同的HWID不会影响我们的驱动卸载质量,但我们没必要增加这额外的重复工作,所以我们有必要整理一下我们刚才获得的HWID列表。另外,由于我们刚才读取的HardwareID键值是一个“REG_MULTI_SZ”类型的键值,所以我们读取的硬件ID是这么一种形式:
HWID1[换行符] HWID2[换行符]……HWIDn
所以我们在整理HWID之前必须将刚才的数据进行一定的转化。
Func _DrvUnins_TidyHwids($HwidList)
Local $tHwidList[1], $tp = 1
Local $i
For $i = 1 To UBound($HwidList, 1) - 1
Local $Hwids = $HwidList[$i][1]
If $Hwids <> "" Then
Local $tArr = StringSplit($Hwids, @LF)
If IsArray($tArr) And $tArr[0] > 1 Then
Local $j
For $j = 1 To UBound($tArr) - 1
ReDim $tHwidList[$tp + 1]
$tHwidList[$tp] = $tArr[$j]
$tp += 1
Next
EndIf
EndIf
Next
;_ArrayDisplay($tHwidList)
Local $i, $j
For $i = 1 To UBound($tHwidList) - 2
For $j = $i + 1 To UBound($tHwidList) - 1
If $tHwidList[$i] <> "" And _
$tHwidList[$i] = $tHwidList[$j] Then
$tHwidList[$j] = ""
EndIf
Next
Next
;_ArrayDisplay($tHwidList)
Local $Hwids[1], $p = 1
Local $i
For $i = 1 To UBound($tHwidList) - 1
If $tHwidList[$i] <> "" Then
ReDim $Hwids[$p + 1]
$Hwids[$p] = $tHwidList[$i]
$p += 1
EndIf
Next
;_ArrayDisplay($Hwids)
Return $Hwids
EndFunc ;==>_DrvUnins_TidyHwids
函数_DrvUnins_TidyHwids的目的是整理刚才我们获得的HWID列表,简单介绍一下:
(1)本函数的第一个循环,将挤在一起的以换行符间隔的HWID转化成独立的;
(2)本函数的第二个循环,通过遍历将重复的ID设置为空字符串;
(3)本函数的第三个循环,将刚才整理过的HWID列表重新填入$Hwids,并跳过空字符串。
(4) 本函数的最终目的是返回一个整洁的本机HWID列表。
3、自动卸载的执行
有了HWID列表,再根据刚才说的DevCon.exe的命令行卸载驱动的功能,我们可以写一个自动根据HWID列表调用DevCon.exe卸载本机驱动的函数了。
Func _DrvUnins_Unins($Hwids, $DevCon)
ProgressOn("驱动卸载", "正在卸载驱动...")
Local $i
Local $Max = UBound($Hwids) - 1
Local $per = 1
For $i = 1 To $Max
$per = Int($i / $Max * 100)
ProgressSet($per, StringReplace($Hwids[$i], "&", "&&"), _
"正在卸载驱动... (" & $per & "%)")
RunWait($DevCon & " remove " & $Hwids[$i], "", @SW_HIDE)
Next
ProgressOff()
EndFunc ;==>_DrvUnins_Unins
_DrvUnins_Unins简介:
(1)本函数有两个形式参数,一个是本机HWID列表$Hwids,一个是DevCon.exe程序的所在位置$DevCon;
(2)本函数通过枚举HWID列表中的每一个HWID来卸载驱动程序;
(3)本函数无返回值,目的是写在本机所有驱动程序。
好了,有了这三个函数,再加上DevCon.exe的强大性能,我们完成了对本机驱动的自动卸载工作。
<ignore_js_op>
(五)常见问题问答
1、为什么执行完毕后我在设备管理器里还是看到很多驱动没有卸载掉?
很多设备是正在被使用的,例如你的CPU、显卡,这些设备如果被卸载掉会直接造成一系列的问题,所以Windows对于这类设备的卸载有着特殊的方针。当硬件正在被使用时其驱动不可被卸载,但这些设备的驱动将在你重启计算机后自动卸载掉。所以无需担心这些设备的驱动。
2、保留PS2鼠标(Mouse)、PS2键盘(Keyboard)、系统设备(System)、系统遗留驱动(LegacyDriver)、硬件抽象层(Computer)设备驱动的目的是什么?
(1)PS2鼠标和PS2键盘,这是没有必要卸载的,你见过谁的机器因为换了个PS2设备蓝屏或冲突吗?那为什么USB的键盘鼠标要卸载掉,这个问题比较难解释,一是很多USB键盘鼠标并不被识别为鼠标,而是被识别为人体学工程设备,在分辨上有些困难;二是某些USB键盘鼠标如果不被卸载,其残留的驱动在部署后对新接入的USB设备有影响(实践中发现的问题,具体原因不明)、
(2)系统设备,这是从XP时代就公认不用卸载的,经过历年实践的检验,完全可以放心。
(3)系统遗留驱动,这个翻译不是十分准确,LegacyDriver设备一般是以前安装过但现在并不在使用的,这类设备的存在不会影响系统部署的成功率。
(4)硬件抽象层(HAL),在上一章中已经叙述,Windows7的HAL只分为X86和X64两个版本,所以我们无需对HAL进行任何更改了。
3、为什么没有将PCI IDE控制器更改为“标准PCI IDE控制器”?
(1)Win6.x这代系统对驱动认证更为严格,而且很多驱动不是你关闭认证就可以真不需要认证的,大家有兴趣可以试试。这为自动更改“标准PCI IDE控制器”行成了阻碍。
(2)更改“标准PCI IDE控制器”这个“行业标准”建立于遥远的XP封装最初时代,这么做的目的已经被传的没有其本意了。经过理论求证和实践操作,一定程度上证明这种更改是没有太大实际意义的,所以我个人一直倾向于将其卸载。大家可以再通过实践来进一步求证。
4、这些代码是否完美?
我不能保证代码的完美性,理论上说这只是一种自动卸载驱动的实现途径,如果大家有兴趣完全可以研究更强大的。但这里必须说一句,不管您有什么想法和理论,必须有长期实践为其撑腰。
5、驱动卸载后我的分区看不到了?
硬盘的分区也是靠驱动来实现的,系统通过驱动看到每个硬盘分区,而如果你在卸载驱动时某个硬盘分区没有正在被使用,则该分区的驱动会立刻被卸载,那么你就看不到这个分区了。这是个很正常的现象,就像卸载声卡后看不到声卡一样,无需担心硬盘分区内的数据,你只是暂时看不到他们了而已。
6、手工卸载VS自动卸载?
如果你实践过本章的代码,你可以很清晰的发现设备管理器里所看到的设备不是当前系统里的所有设备,所以即使你手工根据设备管理器卸载驱动,那么你卸载的是全部驱动吗?当然,自动卸载也不是完美的,人写的程序总会有错误,程序只会按照人的既定思路去做事,不会变通,但不应以此就判定自动卸载是垃圾的,虽然程序是人写的就会有错误,但程序是人写的就可以通过人去完善!
7、驱动卸载要多干净?
之前已经说过,驱动卸载不是必要的过程,而是为了避免细微的问题。而在以往的经历中我发现很多人过于苛求驱动的干净了,很多人往往为了一两个所谓的“幽灵硬件”忧心忡忡,这其实是毫无必要的。
你可以尝试为你的计算机更换一块网卡,你立刻就会看到你前网卡的“幽灵硬件”。“幽灵硬件”这种说法迷惑了太多人,这其实是Windows的一种机制,目的是你再将这个设备换回本计算机时可以立刻启用,简化驱动搜索与安装过程。“幽灵硬件”是一个具有一定偏颇性的叫法,无需过于担心它们的存在,但也别过于放心,某些时候它们的确能引起莫名其妙的问题。
需要下载可以下载最后的附件。
PS:代码不是复制粘贴用的,而是在你看明白后整合到自己的思路里去书写的。复制粘贴永远不能提高技术。
编译好的WIN7驱动卸载程序:
<ignore_js_op>DevUnins.7z (309.93 KB, 下载次数: 2196)
本例中的源代码整合包,额外的执行部分以及DevCon.exe:
<ignore_js_op>DevUnins_Codecs.7z (14.96 KB, 下载次数: 736, 售价: 10 点活跃)
[分享] [3]《步步为营封 Win7》磁盘控制器
Skyfree 发表于 2009-9-13 05:44:22
https://www.itsk.com/thread-20956-1-25.html
(一)概念
关于磁盘控制器驱动,这似乎是个老生常谈的问题了。从大概两年前我就一直在努力的纠正“SATA驱动、串口驱动”这些概念错误,但效果不佳,直至今日仍有部分技术人员将这些具有很大偏颇性的词语挂在嘴边,乃至误导更多的新手。所以今天我会再次重复强调一下“磁盘控制器”和“磁盘控制器驱动”的概念,新手请务必读懂,老手也有必要进行重温。
什么是磁盘控制器?从字面上也大概可以看出,磁盘控制器的作用是管理和控制磁盘。这里的“磁盘”是一个广义的概念,泛指现在常用的机械硬盘和固态硬盘。磁盘控制器有集成于主板上的,也有独立的(如各类SCSI卡),而且磁盘控制器是由来已久的,不是到“SATA时代”才开始出现的。我们这里一定要搞清楚三个问题:
1、磁盘控制器与磁盘无关。
系统是通过磁盘控制器来识别磁盘的,所以磁盘控制器上的磁盘无论是什么样子(无论是PATA、SATA、RAID、SCSI以及等等)系统是绝对不会操心的,系统唯一关心的是它能否识别磁盘控制器,如果能识别磁盘控制器那么磁盘控制器就会告诉系统怎么去管理磁盘。
这就好像以为领导要找一份档案材料,他只要找的到档案室的管理员就可以,至于这个档案室管理员去什么样的档案柜上怎么去找档案材料,领导是无需担心的。就像系统无需操心磁盘类型是一样的。
原版系统中(无论是WINXP还是WIN7)都会包含一定量的磁盘控制器驱动,这些驱动可以应付部分磁盘控制器,而且一般而言,应付并口磁盘控制器是没有什么问题的。但随着时间的推移,随着新硬件和新磁盘控制器的推出,系统自带的磁盘控制器驱动会越来越显得单薄,这就是为什么我们在系统封装与部署时必须增补额外磁盘控制器驱动的原因。
2、磁盘控制器驱动是针对磁盘控制器的。
上文已述,系统并不关心磁盘是什么样的,而系统只需要能够控制磁盘控制器就可以了。那么系统要怎么才能拥有对磁盘控制器的控制能力?答案就是通过驱动程序。系统通过磁盘控制器驱动获得对磁盘控制器的控制能力,从而控制磁盘。
3、磁盘控制器工作模式与磁盘类型无关。
现在硬盘的各种标识让人眼花缭乱,而各种关于磁盘控制器工作模式的描述又让人产生各种混淆,SATA、SATAII、AHCI、RAID以及等等,但我这里要说的是,你的硬盘是SATA那么系统就真的把你的硬盘当做SATA了吗?答案为否。
刚才已经说了,系统通过磁盘控制器了解磁盘,而磁盘控制器又有着多种工作和控制模式。在CMOS里我们可以看到对磁盘控制器的设置,大多磁盘控制器拥有多种工作模式,例如IDE模式、AHCI模式、RAID模式等等。如果你是一个SATA硬盘,而磁盘控制器开启的是IDE模式,那么很遗憾,系统仅仅把你的硬盘当做普通IDE硬盘来对待。建议,如果您的硬盘支持更高级的工作模式,请把CMOS里的设置也相应调整以提高磁盘性能。
说完这些概念,我请大家在今后不要再谈论所谓“SATA硬盘驱动”了,这句话带有很大的错误性,并容易误导更多的新手!
(二)磁盘控制器驱动
封装用磁盘控制器驱动(俗称SRS驱动)和即插即用磁盘控制器驱动还是有区别的。
封装用磁盘控制器驱动属于系统关键设备驱动,随系统启动而启动,属于不可或缺的驱动,如果没有这个驱动系统就无法控制磁盘控制器,从而无法操作磁盘,结果就是造成系统的宕机。即插即用磁盘控制器驱动则不同,它就像显卡和声卡的驱动一样,不安装仅仅是无法发挥硬件的最大效能而已,例如显卡驱动不装各种效果无法开启、声卡驱动不装会无声音等。但封装用磁盘控制器驱动和即插即用磁盘控制器驱动本身是无区别的,所以这只是同一种驱动的两种工作模式罢了。
那么封装用磁盘控制器驱动是怎么工作的呢?
1、系统启动时检测系统关键设备列表,并准备将这个列表中的设备启动起来,这个列表在注册表中的:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase
打开CriticalDeviceDatabase键,其下是所有系统关键设备的硬件ID。而我们看一个一硬件ID名命名的键,一般包括ClassGUID和Service子键,键值为拥有此硬件ID的设备的设备所属类和所调用的系统服务。
如果当前磁盘控制器存在于系统关键设备中,那么就根据磁盘控制器硬件ID的Service键去寻找它所需要使用的服务。而如果当前磁盘控制器不存在于系统关键设备中,则直接蓝屏宕机。
2、使用磁盘控制驱动服务,系统的所有服务都位于:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services
当然也包括磁盘控制器驱动的服务。而如果当前磁盘控制器所需要的驱动服务并不存在,则直接蓝屏宕机。
我们打开一个磁盘控制器驱动的服务,这个服务包括很多子键,但其中较为重要的是ImagePath和Start,它们分别规定了本服务要加载哪个驱动文件和本服务的启动方式。
3、加载磁盘控制器驱动文件,启用磁盘控制器。由启动的磁盘控制器驱动服务决定加载哪个驱动文件,这些驱动文件一般都位于C:\Windows\System32\drivers中,而如果这个驱动文件在被加载的时候不存在,则直接蓝屏宕机。
通过如上描述,我们发现了如下一个过程:
系统关键设备-->设备驱动服务-->设备驱动文件。
(1)当前磁盘控制器是否属于系统关键设备,不属于则宕机,属于则根据系统关键设备列表中的相应描述,去寻找这个磁盘控制器所对应的驱动服务;
(2)如果找不到这个磁盘控制器所对应的驱动服务,则宕机,找得到则根据驱动服务中规定的驱动文件,去寻找这个磁盘控制器所对应的驱动文件;
(3)如果找不到驱动文件,则宕机,找得到则使用此驱动控制磁盘控制器。
这是个连贯的过程,哪一个环节出现问题,最终的结果都是宕机。
(三)INF阅读术
阅读驱动的INF文件需要一定的经验积累,同样也需要一定的尝试和失败,所以我这里只能以制作封装用磁盘控制器驱动为目的的INF阅读方法。
以下我以INTEL AHCI磁盘控制器驱动为例介绍,INTEL的驱动写的标准且简介,而且INTEL驱动本身是最为稳定的,建议新手练手时选取INTEL的驱动。
1、读出驱动所属类
[version]
CatalogFile=iaAHCI.cat
Signature="$WINDOWS NT$"
Class=hdc
ClassGuid={4D36E96A-E325-11CE-BFC1-08002BE10318}
Provider=%INTEL%
DriverVer=06/04/2009,8.9.0.1023
version段一般在驱动INF的开头处,Class即为本驱动所属类,而ClassGuid是这个类的GUID。驱动所属类是个重要的信息,在我们制作封装用磁盘控制器驱动的系统关键设备部分有着很重要的地位。
2、读出哪些硬件ID对应本驱动,而每个硬件ID又使用了哪个驱动服务
这一般需要去读两个段,一个是:
[Manufacturer]
%INTEL%=INTEL_HDC,ntx86
Manufacturer段规定了如下哪个段是用来记录驱动描述、所用服务、驱动ID的。“INTEL_HDC”是主段名,“,”后面的是附加段名。例如在这个描述中,如下可能有两个段包括驱动描述、所用服务和驱动ID信息:INTEL_HDC段,或INTEL_HDC. ntx86段。
INTEL的磁盘控制器是一体化的驱动,从XP到WIN7用的驱动是相同的,所以它的Manufacturer段的内容比较简单。有些驱动针对不同系统是分开的,可能会有针对XP和WIN7的不同设置,请根据实际情况进行应变。
另一个需要我们阅读的段十分重要,这个段也是由Manufacturer段规定出来的:
[INTEL_HDC.ntx86]
%PCI\VEN_8086&DEV_2681&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_2681&CC_0106
%PCI\VEN_8086&DEV_27C1&CC_0106.DeviceDesc% = iaStor_Inst,PCI\VEN_8086&DEV_27C1&CC_0106
%PCI\VEN_8086&DEV_27C5&CC_0106.DeviceDesc% = iaStor_mobl_Inst,PCI\VEN_8086&DEV_27C5&CC_0106
%PCI\VEN_8086&DEV_2821&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_2821&CC_0106
%PCI\VEN_8086&DEV_2829&CC_0106.DeviceDesc% = iaStor_mobl_Inst, PCI\VEN_8086&DEV_2829&CC_0106
%PCI\VEN_8086&DEV_2922&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_2922&CC_0106
%PCI\VEN_8086&DEV_2929&CC_0106.DeviceDesc% = iaStor_mobl_Inst, PCI\VEN_8086&DEV_2929&CC_0106
%PCI\VEN_8086&DEV_3A02&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_3A02&CC_0106
%PCI\VEN_8086&DEV_3A22&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_3A22&CC_0106
%PCI\VEN_8086&DEV_3B29&CC_0106.DeviceDesc% = iaStor_mobl_Inst, PCI\VEN_8086&DEV_3B29&CC_0106
%PCI\VEN_8086&DEV_3B2F&CC_0106.DeviceDesc% = iaStor_mobl_Inst, PCI\VEN_8086&DEV_3B2F&CC_0106
%PCI\VEN_8086&DEV_3B22&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_3B22&CC_0106
“=”前的部分是关于这个驱动的文字描述,我们可以在INF的String段里看到,不过这个对我们制作封装用磁盘控制器驱动基本没什么作用。
“=”后的部分,“,”前是针对本硬件ID哪些段对它进行了处理,例如“iaStor_Inst”,如下各段中凡以此开头的,都是针对本硬件ID的处理,包括为本硬件ID添加哪个服务。
“=”后的部分,“,”后是磁盘控制器的硬件ID,如“PCI\VEN_8086&DEV_3B29&CC_0106”。
这些磁盘控制器的硬件ID将在随后被我们添加到封装用磁盘控制器驱动的系统关键设备中,而它们所对应的服务将是我们下一步阅读的目标。
3、读出硬件所对应的服务。
在刚才的INTEL_HDC.ntx86段中,我们获得了本驱动可支持的硬件ID列表,现在我们要把这些ID对应的服务找出来。例如:
%PCI\VEN_8086&DEV_3A22&CC_0106.DeviceDesc% = iaStor_Inst, PCI\VEN_8086&DEV_3A22&CC_0106
规定了PCI\VEN_8086&DEV_3A22&CC_0106的各类操作由iaStor_Inst相关段决定,那我们就去寻找iaStor_Inst的相关段,直到找到:
[iaStor_Inst.Services]
AddService = iaStor, %SPSVCINST_ASSOCSERVICE%, iaStor_Service_Inst, iaStor_EventLog_Inst
本段中决定要添加一个服务(AddService),名为“iaStor”,添加方法由“iaStor_Service_Inst”段决定,添加的事件日志由“iaStor_EventLog_Inst”段决定。随后我们找到“iaStor_Service_Inst”段。
[iaStor_Service_Inst]
DisplayName = %*PNP0600.DeviceDesc%
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_BOOT_START%
ErrorControl = %SERVICE_ERROR_NORMAL%
ServiceBinary = %12%\iaStor.sys
LoadOrderGroup = SCSI Miniport
AddReg = iaStor_parameters_AddReg
DisplayName,服务的显示名,这对我们制作封装用磁盘控制器驱动没太大关系。
ServiceType,服务的类型,这里是“内核级驱动”。
StartType,服务启动类型,这里是“随系统启动”。
ErrorControl,报错类型,这里是“一般性报错”。
ServiceBinary,这个其实是驱动文件的位置,%12%代表System32\drivers,则完整驱动文件路径为“System32\drivers\iaStor.sys”。
LoadOrderGroup,驱动所属的组。
AddReg,这一般是为本服务额外添加的注册表键和键值。
通过阅读这些,我们知道了硬件ID为“PCI\VEN_8086&DEV_3A22&CC_0106”的设备所需服务的基本概况,特别是我们得知了这个驱动服务所加载的驱动文件名称及位置。以此类推,解决其他的硬件ID。
从INF里读到了这些信息,我们就可以着手制作WIN7的封装专用磁盘控制器驱动了。
(四)制作封装专用磁盘控制器驱动
制作封装专用磁盘控制器驱动其实就是一个将INF转成REG的过程,曾经有过这种工具,但我个人并不建议大家使用。如果使用者并不明白INF转REG的真正原理,就很难了解这项技术的真正内在本质,更难于在出现问题时能够独立解决,这个技术的公共交流带来了很多不便。本节内容我会和大家一起亲手将INTEL AHCI磁盘控制器驱动的INF转成封装用的REG文件,以让大家更加了解这项技术的本质。
上文中,我们已经介绍了INF阅读的基本方法,下面我们来对INF进行一下转化。
1、系统关键设备部分
这部分的注册表键和键值遵守如下样式:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\(硬件ID)]
"ClassGUID"="(类的GUID)"
"Service"="(对应的服务名)"
硬件ID,读取自INTEL_HDC.ntx86段,例如“PCI\VEN_8086&DEV_2922&CC_0106”
类的GUID,读取自version段,“ClassGuid={4D36E96A-E325-11CE-BFC1-08002BE10318}”
对应的服务名,读取自INTEL_HDC.ntx86段,由“PCI\VEN_8086&DEV_2922&CC_0106”对应的iaStor_Inst段所派生的iaStor_Inst.Services决定服务名,为“iastor”。
那么“PCI\VEN_8086&DEV_2922&CC_0106”的系统关键设备部分注册表应该写为:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\ PCI#VEN_8086&DEV_2922&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"=" iastor "
(注意硬件ID中的“\”变为“#”)
以此类推,将其他硬件ID的系统关键设备的注册表键和键值写完。
2、驱动服务部分
上文说过,驱动服务部分由iaStor_Service_Inst来定,服务部分的注册表写起来比较容易,但要注意对应关系,即INF中的名字和REG中的名字不同。
回顾一下iaStor_Service_Inst段,依据此段写封装用磁盘控制器驱动的驱动服务时,不是所有的部分都需要,我将它简化一下:
[iaStor_Service_Inst]
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_BOOT_START%
ErrorControl = %SERVICE_ERROR_NORMAL%
ServiceBinary = %12%\iaStor.sys
LoadOrderGroup = SCSI Miniport
INF中带有“%%”的部分,在INF的String段有期对应的值,最简单的方法可以全文搜索一下两个“%”之间的内容,即会找到他们对应的值。如本例中,替换为值后为:
[iaStor_Service_Inst]
ServiceType = 1
StartType = 0
ErrorControl = 1
ServiceBinary = system32\drivers\iaStor.sys
LoadOrderGroup = SCSI Miniport
这些部分在注册表中分别对应:
INF中的ServiceType对应注册表中的Type;
INF中的StartType对应注册表中的Start;
INF中的ErrorControl对应注册表中的ErrorControl;
INF中的ServiceBinary对应注册表中的ImagePath;
INF中的LoadOrderGroup对应注册表中的Group。
而服务部分的一般样式为:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\(服务名)]
"ErrorControl"=
"Group"=""
"ImagePath"=""
"Start"=
"Type"=
则我们转化后为:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\iaStor]
"ErrorControl"=dword:00000001
"Group"="SCSI Miniport"
"ImagePath"="system32\drivers\IaStor.sys"
"Start"=dword:00000000
"Type"=dword:00000001
这样,服务部分我们也搞定了。
3、驱动文件
差点忘记了,不要忘记把驱动程序文件“IaStor.sys”也提取出来,在执行系统封装时复制到“ImagePath”所规定的位置即可。
经过全部过程后,我们可以制作出来一份INTEL AHCI磁盘控制器的封装用磁盘控制器驱动了!这份驱动的注册表文件为:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_2681&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_27C1&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_27C5&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_2821&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_2829&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_2922&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_2929&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_3A02&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_3A22&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_3B29&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_3B2F&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#VEN_8086&DEV_3B22&CC_0106]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="iaStor"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\iaStor]
"ErrorControl"=dword:00000001
"Group"="SCSI Miniport"
"ImagePath"="system32\drivers\IaStor.sys"
"Start"=dword:00000000
"Type"=dword:00000001
至此,我们学会了制作封装用磁盘控制器驱动的方法。制作封装用磁盘控制器驱动需要长期的实践和总结,也需要经历无数的失败才能成就最后的成功!
INTEL WIN7 磁盘控制器驱动: <ignore_js_op>[DRV]INTEL.7z (334.39 KB, 下载次数: 704)
INTEL WIN7 封装用磁盘控制器驱动: <ignore_js_op>[SRS]Intel.7z (155.49 KB, 下载次数: 546, 售价: 10 点活跃)
支持天空联盟,请单击 http://www.2345.com/?751,这将为天空联盟带来收益!
[分享] [4]《步步为营封 Win7》初级部署控制
Skyfree 发表于 2009-9-13 06:09:33
https://www.itsk.com/thread-20959-1-25.html
在Windows XP封装时代,我们用Sysprep.inf来控制部署过程中的基本问答部分,以实现基本的无人值守安装。
到了Windows Vista/2008/7这代系统以后,微软改用了文件映像系统安装方式、大幅的改进了系统部署过程中的各种控制项目,微软也提供了“Windows系统映像管理器(Windows System Image Manager,简称SIM)”来实现对Windows Vista/2008/7这代系统部署过程的控制,SIM所能管理的项目种类繁多,如果能够得心应手的使用SIM那么对系统各方面的控制将会达到一个不错的高度。
SIM用来生成一个XML文件,此文件可以用于普通系统安装或系统封装部署中的各种控制项目,我们讨论的是系统封装与部署,所以今天我们所讨论关于SIM的使用均是以“为实现更方便快捷的系统封装与部署”为核心来进行的。有关SIM的进一步使用,请大家逐步摸索,今天我们只研究在系统封装部署最常用的部分。
如果需要SIM,那么您将需要下载WAIK包,下载方法在此帖中有更详细的描述:http://bbs.itiankong.com/thread-20961-1-1.html
WAIK中包含很多与Windows系统映像定制相关的内容,包括完整全面的帮助文档,选中不解的部分F1一下会更快得到答案。
一)SIM的基本使用
下载WAIK,安装完毕后,打开SIM,进入如下界面:
<ignore_js_op>
菜单栏,【文件】,【新建应答文件】,这时会提示:
<ignore_js_op>
单击【是】,选择系统映像(Windows7的系统映像可以到Windows7系统光盘的source目录提取):
<ignore_js_op>
选中系统映像,SIM经过检测后会询问你要以这个映像中的哪个版本为依据进行设置,选择与您对应的版本,例如Ultimate:
<ignore_js_op>
【确定】后SIM会有相应的改变:
<ignore_js_op>
SIM中我们最常用的有:
1、左下角的【Windows 映像】,这里可以选择我们要进行设定的模块
2、中间靠上部分的【应答文件】,这里我们会以树状结构预览到我们的各项设定,包括如下时机:
(1)【windowsPE】,众所周知Windows7在安装前会启动一个WINPE环境以执行系统安装,这个设定就是关于这个PE的
(2)【offlineServicing】,这部分设定是关于离线服务的,一般用不到
(3)【generalize】,这部分设定很重要,关于一般系统部署过程的
(4)【sepcialize】,这部分设定很重要,关于特殊系统部署过程的
(5)【auditSystem】和【auditUser】,这两部分是关于系统审核的,一般用不到
(6)【oobeSystem】,这部分设定很重要,关于OOBE过程的
3、右侧的【属性】,这里用于设定每个选项的具体属性
SIM遵循这样一种过程,在【Windows 映像】中选择要设定的模块,将选中的模块传送到【应答文件】中适当的实机,后在【属性】中对刚刚传送来的实机进行详细设定。
下面我就以实例讲解使用SIM的一般过程:
第一,添加要在“部署中”调用的程序
【Windows 映像】Components中选择“Windows-Deployment”模块,并右键单击其下的:“RunSynchronous”子模块,单击【添加设置传送到sepcialize】
(RunSynchronous和RunAsynchronous的功能是相同的,都是添加调用程序,但RunSynchronous是逐个运行的,而RunAsynchronous是不等待上一个运行结束即运行下一个的)
<ignore_js_op>
右键【应答文件】中刚传送来的RunSynchronous,单击【插入新建RunSynchronousCommand】,以创建新的调用
<ignore_js_op>
单击刚刚添加的RunSynchronousCommand,在右侧的【属性】部分设置其属性,主要有设定:
Description(描述):我们设定为“InDeploy”
Order(被调用的顺序):我们设定为“1”
Path(要调用的程序名):我们设定为“%WinDir%\Test -InDeploy”
<ignore_js_op>
如果有更多调用,请仿照这个过程,添加更多程序就可以了,注意设定一下Order属性
第二,添加“首次登录”调用的程序
【Windows 映像】Components中选择“Windows-Shell-Setup”模块,并右键单击其下的:“FirstLogonCommands”子模块,单击【添加设置传送到oobeSystem】
<ignore_js_op>
右键【应答文件】中刚传送来的FirstLogonCommands,单击【插入新建SynchronousCommand】,以创建新的调用
<ignore_js_op>
单击刚刚添加的SynchronousCommand,在右侧的【属性】部分设置其属性,主要有设定:
Description(描述):我们设定为“FirstLogon”
Order(被调用的顺序):我们设定为“1”
CommandLine(要调用的程序名):我们设定为%WinDir%\Test.exe -FirstLogon”
<ignore_js_op>
如果有更多调用,请仿照这个过程,添加更多程序就可以了,注意设定一下Order属性
第三,添加“进入桌面后”调用的程序
【Windows 映像】Components中选择“Windows-Shell-Setup”模块,并右键单击其下的:“LogonCommands”子模块,单击【添加设置传送到oobeSystem】
<ignore_js_op>
右键【应答文件】中刚传送来的LogonCommands,单击【插入新建AsynchronousCommand】,以创建新的调用
<ignore_js_op>
单击刚刚添加的AsynchronousCommand,在右侧的【属性】部分设置其属性,主要有设定:
Description(描述):我们设定为“Go2Desktop”
Order(被调用的顺序):我们设定为“1”
CommandLine(要调用的程序名):我们设定为“%WinDir%\Test.exe -Go2Desktop”
<ignore_js_op>
如果有更多调用,请仿照这个过程,添加更多程序就可以了,注意设定一下Order属性
第四,添加OOBE阶段设定项目
【Windows 映像】Components中选择“Windows-Shell-Setup”模块,并右键单击其下的:“OOBE”子模块,单击【添加设置传送到oobeSystem】
<ignore_js_op>
单击刚传送到【应答文件】中的OOBE部分,查看右侧【属性】部分进一步设定:
HideEULAPage:设定为true,即为跳过协议界面;设定为false,则不跳过
HideWirelessSetupInOOBE:设定为true,即跳过OOBE中的无线设定部分;设定为false,则不跳过
NetworkLocation:有三个值,Home(家庭)、Work(工作)、Other,根据情况设定
ProtectYourPC:1、2、3三个值,对应自动获取所有补丁、自动获取重要补丁、不自动升级三个选项
SkipUserOOBE:跳过用户OOBE过程
<ignore_js_op>
通过这四个例子,我想大家对SIM的使用已经有了一定的熟悉,SIM中还有N多值可以设定,大家可以逐步尝试。如遇到不明确的内容,可以选中选项后按F1,WAIK有详细的帮助文档。
(二)Sysprep3.14的使用
自Windows Vista开始,微软更新了Sysprep程序,版本为3.14。新版Sysprep.exe与以往版本差异很大,参数如下:
/audit
重新启动计算机进入审核模式。审核模式使您可以将其他驱动程序或应用程序添加到 Windows。您还可以在将 Windows 安装发送给最终用户前对其进行测试。
如果指定了无人参与 Windows 安装程序文件,则 Windows 安装程序的审核模式将运行 auditSystem 和 auditUser 配置阶段。
/generalize
准备要作为映像的 Windows 安装。如果指定此选项,所有唯一的系统信息将从 Windows 安装中删除。安全 ID (SID) 重置,所有系统还原点将被清除,事件日志也将被删除。
下次计算机启动时,将运行 specialize 配置阶段。将创建新的安全 ID (SID),如果用于 Windows 激活的时钟三次没有被重置,将其重置。
/oobe
重新启动计算机进入“欢迎使用 Windows”模式。“欢迎使用 Windows”允许最终用户自定义其 Windows 操作系统、创建用户帐户、命名计算机和其他任务。在“欢迎使用 Windows”启动前,将立即处理答案文件中 oobeSystem 配置阶段的所有设置。
/reboot
重新启动计算机。使用该选项审核计算机并确保首次运行体验正确工作。
/shutdown
在 sysprep 命令完成运行后关闭计算机。
/quiet
运行 Sysprep 工具而不显示屏幕确认消息。如果自动运行 Sysprep 工具,则使用该选项。
/quit
运行指定命令后,关闭 Sysprep 工具。
/unattend:answerfile
在无人参与安装期间,将答案文件中的设置应用到 Windows。
answerfile
指定要使用的答案文件的路径和文件名。
读完这些参数的朋友应该注意的到了一点:/unattend:answerfile,举例:/unattend:D:\xxx.xml。到这里大家应该看明白了,微软新一代系统的部署并不是在系统部署过程中才去读取无人值守文件的内容,而是在系统封装时就将这些信息读入了,读入的方法正是使用sysprep3.14的命令行加以设定!
好的,下面我们就来看一个使用sysprep3.14封装系统的实例,以便于更深入的了解这个过程中要注意的问题。
我们在刚才是一共SIM生成无人职守应答文件时,设定了在部署中、首次登录、进桌面调用的名为Test的程序,这个程序我放在了附件里,有需要请下载。注意,如果设定了要运行不存在的程序,则系统部署过程中会直接报错,请特别注意。所以如果你按照刚才SIM的使用实例中设定了调用windows文件夹下的test.exe程序,那么务必在执行下述例子之前将test.exe放入windows文件夹。
1、将我们刚才生成的Untitled.xml放在D盘根目录下,打开命令提示符,运行如下命令:
- c:\windows\system32\sysprep\sysprep.exe /oobe /generalize /quit /quiet /unattend:d:\Untitled.xml
如下图
<ignore_js_op>
2、运行成功,系统封装过程开始
<ignore_js_op>
<ignore_js_op>
由于我设定的是“/quit ”,所以封装后不会重启,在确认无其他调整后,手动重启计算机
3、系统部署到下图阶段时(部署中),会调用我们的test.exe运行
<ignore_js_op>
4、部署完毕进入系统,进入OOBE过程
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
5、OOBE结束,首次登录:
<ignore_js_op>
6、首次登录时调用我们的test.exe
<ignore_js_op>
7、首次进桌面调用我们的test.exe
<ignore_js_op>
1、在尽可能保证稳定的基础上加快系统安装速度,减少重复的机械化的无意义劳动,提高工作效率;
2、降低技术门槛,让需要多步骤执行的过程简化为按几个按钮就能完成的事情。
如果是为了这两个目的考虑,那么我们在学会了基本的部署阶段控制的基础上,就要拓展一些内容了。在上一章里我说过,一般的WIN7封装与部署有两个缺点:
1、使用非ADMIN登陆不符合中国用户的习惯;
2、繁琐的OOBE过程有效的降低了我们的工作效率,增加了不必要的负担。
那么本章的目的就明确了:
1、想办法自动激活ADMIN账户;
2、跳过OOBE过程;
3、接管部署过程以实现1和2。
WIN7的ADMIN账户默认是禁用的,我们可以在封装前将其设置为启用,而后方便我们的自动化封装工作。
但烦人的问题也随即出现了,ADMIN账户在封装后又会自动改为禁用。本想大不了在封装后再手工开启呗,结果发现部署完成后ADMIN账户又自动禁用了(无语……)。好吧,看来微软是无论如何也要禁用ADMIN了,那么这个问题就由我们来解决吧。
1、激活 ADMIN 账户的方法
这个并不复杂,其实只需要一行批处理命令就可以了:
- net user Administrator /Active:yes
AU3的写法是:
- RunWait(@ComSpec & " /c " & "net user Administrator /Active:yes", "", @SW_HIDE)
2、激活 ADMIN 的时机
系统部署到进入桌面的过程大致为:
系统部署-->重启-->系统OOBE-->首次登录-->桌面
在“系统部署”这个步骤完成后系统会自动禁用ADMIN账户,而我们如果跳过了OOBE过程,就直接到了“首次登录”这个步骤。但这样就造成了问题,即ADMIN没有被激活,跳过OOBE后又没有新账户可以用(除非封装前残留了其他账户),这样就造成了系统内无可用用户!这个后果就严重了,没有用户可用,也无法创建新用户,那么这个系统就无法被登录和使用,则这个系统就成了名副其实的废物……
我们通过SIM设定后,系统部署中、首次登录、桌面我们都有可用接口,但自动禁用ADMIN是在部署后执行的,而由于我们跳过了系统OOBE过程,则我们又必须在首次登录前就激活ADMIN,所以系统部署中、首次登录、桌面三个接口我们都无法使用。我们需要这样一个时机,即在系统部署完成后(即windeploy.exe运行完毕后,随后详解)ADMIN被禁用后,执行ADMIN的激活,才能达到我们需要的目的。
这样我们就需要更强大的部署过程控制能力,以实现部署后这个程序调用接口(当然,顺道我们也可以实现部署前程序调用接口)。至于详细怎么做,本章第“(三)”部分会详细说明
这个的实现相对简单,回想上一章我们使用SIM设定OOBE功能模块的时候,OOBE部分有一个属性叫做“SkipMachineOOBE”。
根据说明上说,SkipMachineOOBE是在WIN7测试时才使用的一个参数,在一般的系统安装中是被废弃的属性。但实践证明,在系统部署过程中这个选项可以有效的跳过OOBE过程。实践出真知,无论它本来的设计意图是什么,只要能够实现我们的目的,就是好功能,没有必要过于拘泥于理论。
在SIM中我们将OOBE模块的SkipMachineOOBE设置为“true”
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/09091306005107ee565e85940e.png)
SkipMachineOOBE一旦被设置为“true”,OOBE过程就会被跳过,则OOBE部分的其他设定就没有太多意义了,所以我取消OOBE的其他设定。
保存,系统封装时使用这个xml配置文件,就会跳过系统OOBE过程。
需要注意的是,如果没有自动激活ADMIN且封装前系统内没有余留其他用户,则不要使用此功能。原因在“(一)”中我已经说明。
系统封装与部署主要就是执行了两个程序:
1、system32\sysprep\sysprep.exe,运行这个程序执行系统封装,我们已经很熟悉这个了
2、system32\oobe\windeploy.exe,系统进入系统部署模式后,自动运行这个程序以完成系统部署中的各项功能
那么,系统是如何知道进入系统部署模式后要运行哪个程序那?或者说,系统是怎么知道要运行windeploy.exe以完成系统部署的?
打开注册表“HKEY_LOCAL_MACHINE\SYSTEM\Setup”,看一下“Setup”键的键值,一般为“oobe\windeploy.exe”,这下我们明白了,是这个键值规定了要执行什么。那么如果我们加入了自己写的部署控制程序,又更改这个键值指向我们的程序,是不是就可以接管部署过程了?答案是“可以”。
为了更好测试,我们以批处理的方式来实现。写如下批处理,名为deploy.cmd:
- start /wait %windir%\system32\oobe\windeploy.exe
- net user Administrator /Active:yes
好的,我们来实践一下。首先我们运行sysprep.exe执行系统封装,别忘记加载我们刚才生成的用于跳过OOBE过程的无人值守xml文件,一定要设置封装完毕后退出,以方便其后的设定。(如果xml中还规定了调用其他程序,例如上一章的test.exe,别忘记将test.exe放入所规定的windows文件夹)
封装完毕后,打开注册表编辑器,到“HKEY_LOCAL_MACHINE\SYSTEM\Setup”键下
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/0909130604cea026b3aea951c1.png)
将setup键值改为“deploy.cmd”
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/090913060468d9a1f30e758464.png)
而后将deploy.cmd复制到system32目录下。(setup键值规定的程序是以system32为起始目录的,不可使用绝对路径)
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/090913060416024764aa3855f2.png)
完成后,重启计算机,进入系统部署过程。可以看到我们写的批处理接管了部署过程,由我们的批出里调用windeploy执行部署过程,windeploy执行完毕后还会由命令行自动激活ADMIN。
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/090913060430092db698eb03d3.png)
(自动激活ADMIN的过程太快,没截出图来……)
部署完成后,重启计算机,自动跳过OOBE过程,直接以ADMIN登陆系统
<ignore_js_op>
![](https://img.itsk.com/itkdx/attachment/forum/month_0909/09091306044addb3f6461e6a5b.png)
到这里,我们就用最原始的批处理完成了对WIN7部署过程的接管。如果您讨厌批处理的黑框,可以尝试用AU3等写一个类似的程序。
有的朋友可能要问了,那部署前接口怎么实现?这个简单,只要是运行于“start /wait %windir%\system32\oobe\windeploy.exe”之前的不就是部署前调用吗?以后我们可以很方便的在windeploy.exe运行前执行例如驱动解压等过程,就像现在XP部署过程一样。
最基本和最核心的方法我已经带给了大家,大家想开出什么花,由大家自己发挥吧!
到这里,《步步为营封 Win7》也要画上句号了,感谢这些天来大家的阅读和支持,衷心的希望大家个个都能成为高手,共同创建最佳的学习环境。
支持天空联盟,为联盟带来收益,请单击 http://www.2345.com/?751