在上一篇打包阿里云驱动的文章中,文章的最后留下了一个疑问,如何针对2016系统放文件。尝试了很多种方式。
1.最开始想着InstallShield有一个结构体叫SYSINFO,天真的以为可以利用SYSINFO.nWinMajor和SYSINFO.nWinMinor,或者SYSINFO.nOSMajor和SYSINFO.nOSMinor判断系统内核版本是不是大于6.3,或者说等于10.0。于是乎有了以下的InstallScript代码:
//调试打印输出用 Sprintf(systemWinVersion, "nWinMajor is = %d , nWinMinor is = %d .", SYSINFO.nWinMajor, SYSINFO.nWinMinor); Sprintf(osWinVersion , "osMajor is = %d , osMinor is = %d .", SYSINFO.nOSMajor, SYSINFO.nOSMinor); MessageBox(systemWinVersion,WARNING); MessageBox(osWinVersion,WARNING); //如何MajorVersion等于10,则为2016系统 if(SYSINFO.nWinMajor == 10) then InstallAllSys2016Drivers(); else InstallAllDrivers(); endif;
但是很不幸的是,无论是systemWinVersion还是osWinVersion对于2016系统输出的都是6.3,即和2012R2系统一致。曾经一度以为自己装了一个假的2016系统。再来,发现InstallShield功能还是很强大的,可以使用自家的UseDLL API直接调用dll动态库,然后使用dll中的函数,在查阅MSDN的过程中,发现微软的Kernel32有两个API函数用来判断操作系统版本,分别是IsWindows10OrGreater和IsWindowsVersionOrGreater。于是乎又有了下面的InstallScript代码:
#define DLL_FILE "Kernel32.dll" prototype Kernel32.IsWindows10OrGreater(); prototype Kernel32.IsWindowsVersionOrGreater(SHORT,SHORT,SHORT); nResult = UseDLL(DLL_FILE); if(nResult = 0) then MessageBox("Successfully use Kernel32.dll",SEVERE); else MessageBox("Failed use Kernel32.dll",SEVERE); endif; if(IsWindowsVersionOrGreater(10,0,0)) then MessageBox("This is Windows 2016", SEVERE); InstallAllSys2016Drivers(); else MessageBox("This is not Windows 2016", SEVERE); InstallAllDrivers(); endif; if(UnUseDLL(DLL_FILE) < 0) then MessageBox("UnuseKernel32 failed ", SEVERE); else MessageBox("UnuseKernel32 Successful ", SEVERE); endif;
代码似乎又跟我开了一个玩笑,这两个API依然无法判断系统是否为2016,继续浏览MSDN,发现一个GetVersionEx函数,下面的描述让我很是拨凉拨凉~~~微软自己在Win10/Server2016里面埋下了一个坑,除非用C++加上manifest文件来实现。不然直接获取系统内核版本号返回的就是Win8/Server2012R2的版本号。
经历了坑之后,就想着这只能使用C++来写个可执行exe来实现这个功能了,后来发现InstallShield还有一个函数叫LaunchAppAndWait,这个函数类似于Windows C++的CreateProcess函数,是InstallShield调用可执行文件的API,但是当时网上对于这个API的描述太少,InstallShield自己的帮助文档也对LaunchAppAndWait的返回值描述的很模糊。当时就想着C++写一个函数,是2016系统返回非0,不是2016系统返回0,这个LaunchAppAndWait的返回值是不是就是可执行程序的返回值。后来自己用C++写了一个判断2016系统的程序,具体C++代码可以参考我的博客《使用WMI获取Windows操作系统内核版本号(C++实现)》,然后InstallScript代码如下:
if(SYSINFO.bIsWow64) then szProgram = "\"" + TARGETDIR^"JudgeSystem2016.exe\""; nResult = LaunchAppAndWait(szProgram,"",nOptions); if(nResult = 2) then MessageBox("The system is 2016!",INFORMATION); InstallAllSys2016Drivers(); else MessageBox("The system is 64 bit system!",INFORMATION); InstallAllDrivers(); endif; else MessageBox("The system is 32 bit system!",INFORMATION); InstallAllDrivers(); endif;
经过了这次尝试我是发现了LaunchAppAndWait这个函数只会返回0跟非0,非0代表执行失败。当时真的非常失望,最后还是打开了cmd窗口,输入了ver命令,发现了惊喜。
这好像可以写一个批处理程序啊,于是说干就干,批处理代码如下:
@echo off echo 当前路径: %~dp0 ver|findstr /r /i " [版本 10.0.*]" > NUL && goto WindowsServer2016 goto WindowsServerOther :WindowsServer2016 if exist "%~dp02016SysDriver" (xcopy "%~dp02016SysDriver\*" "%~dp0" /s /e /y /q) rd /s /Q "%~dp02016SysDriver" >nul 2>nul goto End :WindowsServerOther rd /s /Q "%~dp02016SysDriver" >nul 2>nul :End exit @echo on终于,烦人的2016系统特殊处理问题终于解决了,在下一篇文章《使用InstallShield制作Windows阿里云Virtio驱动安装包(三)-- 安装和卸载驱动》中我会描述使用InstallScript代码安装和卸载驱动程序。