驱动安装+打包程序
来源:互联网 发布:软件项目经理绩效考核 编辑:程序博客网 时间:2024/04/30 22:56
背景
项目背景为非UVC标准USB工业相机,连接Windows PC,需要安装特定USB驱动。我负责开发PC端相机软件部分(已完成),所以也需要把驱动安装这部分囊括进来。
USB芯片厂商已经提供了winxp/winvista/win7/win8/win8.1/win10、32bits/64bits不同平台的不同驱动文件,包括.inf、.sys、.cat、.dll文件。因此插上相机设备后,可以找到对应平台驱动,通过Windows设备管理器或者右键.inf文件进行驱动的安装。但是这些事情对于开发人员只是鼠标点点的操作,对于用户却会成为很麻烦的事情。因此开发PC端软件的我需要简化驱动安装的一切操作,尽量做到对用户透明。
捣鼓了不少时间,写出目前的解决方案。
驱动安装
为了让用户接触不到驱动安装的繁琐操作,只能用代码解决了,解决过程中在《竹林蹊径——深入浅出Windows驱动开发》这本书上受益匪浅,大概阅读,也算是加深了硬件设备与Windows系统间连接过程的理解。
开发环境win8.1 vs2013 c++ 控制台应用程序(有预编译头)
spdlog为日志输出(github开源项目)
使用的ANSI字符串
- 驱动预安装部分,上代码,参考竹林蹊径第12章
API参考链接
该函数成功运行需要程序具有管理员权限,具体可在项目属性->链接器->清单文件->UAC执行级别中更改为requireAdministrator。
BOOL InstallDriver(TCHAR* inf_path, TCHAR* inf_name_out){ /* * inf_path: .inf文件所在路径,例如C:\\driver.inf * inf_name_out: inf文件预安装成功或系统已存在,则返回相应文件名,如oemxx.inf */ TCHAR path1[MAX_PATH] = {0}; TCHAR *path2; if (FALSE == SetupCopyOEMInf(inf_path, NULL, SPOST_PATH, SP_COPY_NOOVERWRITE, path1, MAX_PATH, NULL, &path2)) //需要管理员权限 { DWORD error = GetLastError(); if (error == ERROR_FILE_EXISTS) { spdlog::get("driver_install_info")->info("the driver file has existed, so succeeded"); //cout << "the driver file has existed, so succeeded" << endl; //_tprintf(_T("the oem name is: %s\n"), path2); spdlog::get("driver_install_info")->info("the oem name is: \n" + string(path2)); //cout << path2; //printf("the file name is: %s", path2); _tcscpy_s(inf_name_out, MAX_PATH, path2); return TRUE; } else { spdlog::get("driver_install_info")->info("install failed, "); spdlog::get("driver_install_info")->info("the error code is: " + to_string(error)); //cout << "install failed, "; //cout << "the error code is: " << error << endl; return FALSE; } } else { spdlog::get("driver_install_info")->info("install succeeded\n"); spdlog::get("driver_install_info")->info("the oem name is: " + string(path2) + "\n"); //_tprintf(_T("the oem name is: %s\n"), path2); _tcscpy_s(inf_name_out, MAX_PATH, path2); return TRUE; }}
- 不同平台系统对应不同驱动文件,因此程序中还需要获取系统信息,上代码
API参考链接
/** 该API准确判断系统版本,还需要对程序的manifest文件进行修改,* 也需要有win10 SDK的VersionHelper.h以及sdkddkver.h等头文件适配,具体可以百度*/enum WINDOWS_VERSION{ WINDOWS_XP, WINDOWS_VISTA, WINDOWS_7, WINDOWS_8, WINDOWS_8_1, WINDOWS_10, OTHER_VERSION};WINDOWS_VERSION GetSystemVersion(){ if (IsWindows10OrGreater()) { return WINDOWS_10; } else if (IsWindows8Point1OrGreater()) { return WINDOWS_8_1; } else if (IsWindows8OrGreater()) { return WINDOWS_8; } else if (IsWindows7OrGreater()) { return WINDOWS_7; } else if (IsWindowsVistaOrGreater()) { return WINDOWS_VISTA; } else if (IsWindowsXPOrGreater()) { return WINDOWS_XP; } else { return OTHER_VERSION; }}
- 判断操作系统位数,代码参考于网络,如下
enum WINDOWS_BITS_WIDTH{ WINDOWS_32BITS, WINDOWS_64BITS};// 安全的取得真实系统信息 VOID SafeGetNativeSystemInfo(__out LPSYSTEM_INFO lpSystemInfo){ if (NULL == lpSystemInfo) return; typedef VOID(WINAPI *LPFN_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetNativeSystemInfo"); if (NULL != fnGetNativeSystemInfo) { fnGetNativeSystemInfo(lpSystemInfo); } else { GetSystemInfo(lpSystemInfo); }}// 获取操作系统位数 WINDOWS_BITS_WIDTH GetSystemBits(){ SYSTEM_INFO si; SafeGetNativeSystemInfo(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { return WINDOWS_64BITS; } return WINDOWS_32BITS;}
- 驱动预安装最终代码
int InstallDriver(){ //获取.exe执行文件所在路径 TCHAR path[MAX_PATH] = {0}; GetModuleFileName(NULL, path, MAX_PATH); *(_tcsrchr(path, _T('\\'))) = 0; string msg(path); _tcscat_s(path, MAX_PATH, _T("\\Drivers\\")); //日志初始化 //spdlog::set_async_mode(4096); auto logger = spdlog::basic_logger_st("driver_install_info", msg + "\\driverlog.txt"); spdlog::get("driver_install_info")->info("the driver files' directory is " + msg); //_tcscat_s(path, _T("winxp")); switch (GetSystemVersion()) { case OTHER_VERSION: _tcscat_s(path, MAX_PATH, _T("wxp\\")); msg = "before winxp or windows server \n"; //cout << "before winxp or windows server " << endl; break; case WINDOWS_XP: _tcscat_s(path, MAX_PATH, _T("wxp\\")); msg = "winxp "; //cout << "winxp "; break; case WINDOWS_VISTA: _tcscat_s(path, MAX_PATH, _T("vista\\")); msg = "vista "; //cout << "vista "; break; case WINDOWS_7: _tcscat_s(path, MAX_PATH, _T("Win7\\")); //cout << "win7 "; msg = "win7 "; break; case WINDOWS_8: _tcscat_s(path, MAX_PATH, _T("Win8\\")); msg = "win8 "; //cout << "win8 "; break; case WINDOWS_8_1: _tcscat_s(path, MAX_PATH, _T("Win81\\")); msg = "win8.1 "; //cout << "win8.1 "; break; case WINDOWS_10: _tcscat_s(path, MAX_PATH, _T("Win10\\")); msg = "win10 "; //cout << "win10 "; break; default: msg = "can't find related windows version\n"; //cout << "can't find related windows version" << endl; break; } switch (GetSystemBits()) { case WINDOWS_32BITS: _tcscat_s(path, MAX_PATH, _T("x86\\cyusb3.inf")); msg += "32bits system\n"; //cout << "32bits system" << endl; break; case WINDOWS_64BITS: _tcscat_s(path, MAX_PATH, _T("x64\\cyusb3.inf")); msg += "64bits system\n"; //cout << "64bits system" << endl; break; default: msg += "can't find related machine's drivers of other bits width\n"; //cout << "can't find related machine's drivers of other bits width" << endl; break; } spdlog::get("driver_install_info")->info(msg); msg = ""; TCHAR cur_dir[MAX_PATH] = { 0 }; GetCurrentDirectory(MAX_PATH, cur_dir); spdlog::get("driver_install_info")->info("the current dir is " + string(cur_dir)); //_tprintf(_T("the current dir is: %s\n"), cur_dir); //_tprintf(_T("the .exe dir is: %s\n"), path); BOOL flag = FALSE; TCHAR inf_name[MAX_PATH] = { 0 }; flag = InstallDriver(path, inf_name); //关闭日志 spdlog::drop("driver_install_info"); return 0;}
相机程序安装包制作
利用InstallShield Limited制作,目标点击setup.exe之后,驱动程序、相机程序全部安装。主要在于程序安装之后,驱动程序的自动运行。InstallShield提供了Custom Actions去进行相应操作。如下,打开Custom Actions窗口,添加DriverInstall,相应设置根据图中显示。
日志输出
为了使驱动安装对用户透明,同时输出一定运行调试信息,便于程序出错时查错,因此控制台输出需要替代为日志输出。
这里使用github开源项目spdlog输出日志,用法简单。
遇到的问题与收获
- ansi与unicode字符串的不同
win8.1 sdk没有IsWindows10OrGreater()函数,需要额外加入,还需要添加相应的宏
该问题可以将需要的头文件从win10 sdk复制到项目中,在项目中修改这些文件为需要的版本,如果相应头文件没有复制到项目文件夹根目录下,项目属性需要设置好头文件附加包含目录
所需头文件具体包括sdkddver.h、VersionHelpers.h 、winapifamily.h兼容xp,需要设置平台工具集,由于使用了spdlog,还需要在targetver.h中定义宏
#define _WIN32_WINNT 0x0501
,以使用xp具有的API,该发现源于spdlog\details\os.h代码段#ifdef _WIN32 #if _WIN32_WINNT < _WIN32_WINNT_WS08 TIME_ZONE_INFORMATION tzinfo; auto rv = GetTimeZoneInformation(&tzinfo); #else DYNAMIC_TIME_ZONE_INFORMATION tzinfo; auto rv = GetDynamicTimeZoneInformation(&tzinfo); #endif
- 程序运行不显示控制台窗口,可以在main函数前添加
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
- 驱动安装+打包程序
- 驱动安装和打包
- C# 安装程序打包
- nsis打包安装程序
- VS2010打包安装程序
- Windows打包安装程序
- VC打包安装程序
- 程序安装打包
- vb安装程序打包问题
- vs2008 创建打包安装程序
- C#打包制作安装程序
- C#打包安装卸载程序
- winfrom 程序打包安装方法
- C#打包应用程序(安装程序)
- vs2008 创建打包安装程序
- Ios 程序打包,安装流程
- C#打包安装卸载程序
- iOS 程序打包,安装流程
- mac nmap 的下载
- SQLServer2012通过链接服务器执行SQLServer2000的存储过程的问题
- 今日使用学习MySql指令
- CSS—清除浮动的几种方式
- MockHttpServletRequest对于http前台信息的验证
- 驱动安装+打包程序
- PCR查找、提取、校正
- Android OpenCV Camera preview 横屏以及不全屏的问题
- FME转换CAD至SHP,实现注记到多边形字段传递
- Windows环境下安装Tensorflow
- App一进来是空白页问题
- 改dataTables并实现新的功能
- Retrofit2 源码解析
- Lniux、阿里云配置数据库连接