'use strict' /** * 读取注册表获取纵横软件 * * @author EllisRan. * @date 2018/6/20 * @version */ import db from '../../database' const fs = require('fs') const fse = require('fs-extra') const path = require('path') const ffi = require('ffi') const electron = require('electron') const ipcMain = electron.ipcMain const regeditPath64 = 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall' const regeditPath32 = 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall' const regeditPath = isOSWin64() ? regeditPath64 : regeditPath32 const regedit = require('regedit') let globalNUM = 0 let globalSoftware = [] let globalExe = [] const updateInstall = function (win) { ipcMain.on('updateInstall', function () { regedit.list(regeditPath).on('data', async function (result) { try { // let flag = false // 每次自动获取更新软件内容先让数据库isshow都为false,然后再执行getExeDataList方法里把isshow包含的变true, // 最后再检测把还是false的软件进行判断文件夹和软件是否还在,有则保留,否则删除,完成已删除软件功能(手动添加的exe信息除外) await productAndExeDataIsshow() let softwarelist = result.data.keys let promiseArr = [] let promiseArr2 = [] for (let i in softwarelist) { if (softwarelist[i].indexOf('SmartCost_') !== -1) { promiseArr2.push(getExeDataList(softwarelist[i])) } } await sleep(2000) await Promise.all(promiseArr2) .then(async function (result) { await sleep(5000) if (globalSoftware !== []) { console.log(globalSoftware) for (let i in globalSoftware) { (async function () { globalSoftware[i].exeName = globalExe[i] await promiseArr.push(insertData(globalSoftware[i])) })(i) } } let one = globalSoftware.length console.log(one) await sleep(2000) let two = globalSoftware.length console.log(two) if (one !== two) { console.log(globalSoftware) } await Promise.all(promiseArr) .then(async function (result) { // console.log(globalSoftware) let delnum = await delProductAndExeDataAsync() await db.read().set('sc_hadInstall.first', false).write() let exeInfo = await db.read().get('sc_exeData').last().value() let gourl = exeInfo === '{}' || exeInfo.pid === undefined ? 1 : exeInfo.pid await db.read().set('sc_hadInstall.url', '/softwarestartup/' + gourl).write() if (promiseArr !== undefined && promiseArr.length !== 0) { win.webContents.send('successUpdate', {id: gourl, num: globalNUM, delnum: delnum}) // console.log(globalSoftware) } else { win.webContents.send('failedUpdate', {id: '1', error: 200}) } globalNUM = 0 globalSoftware = [] globalExe = [] }) .catch(function (err) { win.webContents.send('failedUpdate', {id: '1', error: err}) console.log(err) globalNUM = 0 globalSoftware = [] globalExe = [] }) }) .catch(function (err) { console.log(err) }) } catch (error) { console.log(error) } }) }) /** * make all data isshow: true=>false */ async function productAndExeDataIsshow () { await db.read().get('sc_productData').updateWhere({ isshow: true }, { isshow: false }).write() await db.read().get('sc_exeData').updateWhere({ auto: true, isshow: true }, { isshow: false }).write() } /** * delete data by isshow=false * @return {int} */ async function delProductAndExeDataAsync () { // 这里必须静止1s等Promise.all里的getExeDataList方法所有获取执行完才可以获取正确的num,原因不明...... await sleep(1000) let num = await db.read().get('sc_exeData').filter({ auto: true, isshow: false }).size().value() // 先让默认的“未分类” isshow:true,免于被删除,当不存在手动添加的软件或自动检测软件的时候,暂时隐藏“未分类”, // 当启动器不存在任何软件时,默认显示“未分类” // let manualnum = db.read().get('sc_exeData').filter({ auto: false }).size().value() // let flag = db.read().get('sc_productData').getById('1').value().isshow // if (!flag) { // db.read().get('sc_productData').updateById('1', { isshow: true }).write() // } // db.read().get('sc_productData').removeWhere({ isshow: false }).write() // let allnum = db.read().get('sc_exeData').size().value() // if (manualnum === 0 && !flag && allnum !== 0) { // db.read().get('sc_productData').updateById('1', { isshow: false }).write() // } // 对还是isshow:false的软件进行文件夹文件查询,如果还在则保留,不存在则删除 if (num !== 0) { let deleteExeData = await db.read().get('sc_exeData').filter({ auto: true, isshow: false }).value() for (let exe in deleteExeData) { let exePath = path.join(exe.path, exe.exeName) let existExe = await db.read().get('sc_exeData').find({ path: exe.path, exeName: exe.exeName, isshow: true }).value() if (fse.pathExistsSync(exePath) && !existExe) { db.read().get('sc_exeData').updateById(exe.id, { isshow: true }).write() } } } db.read().get('sc_exeData').removeWhere({ auto: true, isshow: false }).write() return num } const sleep = (timeout = 2000) => new Promise(resolve => { setTimeout(resolve, timeout) }) // 取文件名不带后缀 function GetFileNameNoExt (filepath) { if (filepath !== '') { let names = filepath.split('\\') let pos = names[names.length - 1].lastIndexOf('.') return names[names.length - 1].substring(0, pos) } } // 产生随机数函数 function RndNum (n) { let rnd = '' for (let i = 0; i < n; i++) { rnd += Math.floor(Math.random() * 10) } return rnd } /** * 判断文件名是否包含纵横软件exe的部分名称 * @param item * @return {boolean} */ function existSoftwareName (item) { // 纵横软件exe所带包含的文件名 const smartcostSoftwareHeader = ['SmartCost', 'Measure', 'DrawingBuilder', 'BillsEditor'] let flag = false for (let i = 0; i < smartcostSoftwareHeader.length; i++) { if (item.indexOf(smartcostSoftwareHeader[i]) !== -1) { flag = true break } } return flag } function inArray (val, arr) { for (let i in arr) { if (arr[i] === val) { return true } } return false } /** * 数据入库 * */ function insertData (exeData) { return new Promise(resolve => { let pathstr = path.join('data/fileInfo.dll') let libm = ffi.Library(pathstr, { 'GetFileInfo': ['string', ['string']] }) let fileinfo = JSON.parse(libm.GetFileInfo(path.join(exeData.path, exeData.exeName))) exeData.fileVersion = fileinfo.FileVersion exeData.productName = fileinfo.ProductName exeData.productVersion = fileinfo.ProductVersion exeData.fileDescription = fileinfo.FileDescription let dbExeData = db.read().get('sc_exeData').find({ exeName: exeData.exeName, path: exeData.path, fileVersion: exeData.fileVersion }).value() if (dbExeData === undefined || dbExeData === null) { // 先判断是否存在该产品数据库(同时关联到sc_sofeware.json文件数据),再加入安装包数据库 // 新方法,先关联注册表名查找数据,然后再关联产品数据库生成 let softwarejson = path.join('data/sc_software.json') let downlist = fse.readJsonSync(softwarejson).sc_down let downinfo = downlist.find(function (item) { return inArray(exeData.regeditName, item.regedits) }) // let ptitle = downinfo !== undefined ? downinfo.product_title : '' if (downinfo !== undefined) { exeData.simpleName = downinfo.product_title exeData.versionName = downinfo.title let productInfo = db.read().get('sc_productData').find({ product_id: downinfo.product_id }).value() if (productInfo === undefined || productInfo === null) { let scproductlist = fse.readJsonSync(softwarejson).sc_product let scproductInfo = scproductlist.find(function (item) { return item.product_id === downinfo.product_id }) let productInfo2 = scproductInfo productInfo2.addtime = Date.parse(new Date()) / 1000 productInfo2.isshow = true let insertproudct = db.read().get('sc_productData').insert(productInfo2).write() exeData.pid = insertproudct.id productInfo = insertproudct } else { exeData.pid = productInfo.id db.read().get('sc_productData').updateById(productInfo.id, { isshow: true }).write() } // 获取json文件中的锁号,更新到exe当中 for (let j in downlist) { if (productInfo.product_id === downlist[j].product_id && exeData.versionName === downlist[j].title) { exeData.keyNumber = downlist[j].key_number exeData.keytype = downlist[j].keytype exeData.product_id = downlist[j].product_id exeData.down_id = downlist[j].down_id exeData.product_version = fileinfo.FileVersion exeData.show_tip = fileinfo.FileVesrion !== downlist[j].version && exeData.exeName !== 'BillsEditor.exe' exeData.show_updateVersion = downlist[j].version break } } } else { exeData.pid = '1' exeData.simpleName = '' exeData.versionName = '' exeData.keyNumber = '' exeData.keytype = '' exeData.product_id = '' exeData.down_id = '' exeData.product_version = '' exeData.show_tip = false exeData.show_updateVersion = '' db.read().get('sc_productData').updateById('1', { isshow: true }).write() } exeData.addtime = Date.parse(new Date()) / 1000 exeData.isshow = true exeData.auto = true exeData.id = GetFileNameNoExt(exeData.exeName) + '-' + RndNum(10) ++globalNUM db.read().get('sc_exeData').insert(exeData).write() } else { db.read().get('sc_productData').updateById(dbExeData.pid, { isshow: true }).write() db.read().get('sc_exeData').updateById(dbExeData.id, { isshow: true }).write() } resolve(exeData) }) } /** * node 循环和异步解决方案 * @param Info */ function getExeDataList (Info) { return new Promise(resolve => { // setTimeout(function () { regedit.list(regeditPath + '\\' + Info).on('data', async function (result) { let values = result.data.values let regeditData = { path: values['Inno Setup: App Path'].value, name: values['DisplayName'].value, regeditName: Info, fileName: values['Inno Setup: Icon Group'].value } let dirname = await fs.readdirSync(regeditData.path) for (let i in dirname) { if (path.extname(dirname[i]) === '.exe' && existSoftwareName(dirname[i])) { let exeData = regeditData // exeData.exeName = diraname[i] // 这里必须分离2个数组记录值并在外面合并,push才不会出错,否则会重复exeName名,未知bug,坑 globalSoftware.push(exeData) globalExe.push(dirname[i]) } } }) resolve('ok') }) } } /** * 判断系统位数 * @return {boolean} */ function isOSWin64 () { return process.arch === 'x64' || process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432') } export default updateInstall