• electron-vue项目修改注册表在系统右键菜单中添加功能


    一、使用reg文件测试

      reg文件内容:

    Windows Registry Editor Version 5.00
     
    [HKEY_CLASSES_ROOT*shell密存加密command]
    @=""D:\application\secretsave\secretsave.exe" "%1"1"
    [HKEY_CLASSES_ROOT*shell密存解密command]
    @=""D:\application\secretsave\secretsave.exe" "%1"2"

      HKEY_CLASSES_ROOT其实就是HKEY_LOCAL_MACHINESOFTWAREClasses,包含了所有应用程序运行时必需的信息:

      在文件和应用程序之间所有的扩展名和关联; 
      所有的驱动程序名称;   类的ID数字(所要存取项的名字用数字来代替);
      用于应用程序和文件的图标;
      在注册表中HKEY_CLASSES_ROOT是系统中控制所有数据文件的项。这个在Win95和Winnt中是相通的。HKEY_CLASSES_ROOT控制键包括了所有文件扩展和所有和执行文件相关的文件。它同样也决定了当一个文件被双击时起反应的相关应用程序。
      右键菜单的开启

      HKEY_CLASSES_ROOT*shell密存加密command意思是打开cmd

      @=""D:\application\secretsave\secretsave.exe" "%1"1"这句话是cmd里面的命令,应用路径,最后面的1是参数<br>将req文件放在安装好的应用根目录下,右键编辑注册表,修改成功

    二、对参数处理

      在主进程main/index.js里面

    app.on('ready', function () {
      createWindow()
      global.sharedObject = {prop1: process.argv}
    })

      在render的vue文件里接收

    mounted () {
         let args = remote.getGlobal('sharedObject').prop1
         console.log(args)
         let types = ['1','2']
         if (args.length >= 3 && types.includes(args[2])) {
           args[1] = args[1].replace(/\/g, '/')
           this.getArgFile(args)    
         }
    }

      右键点击文件唤起应用时args打印结果

    ["D:applicationsecretsavesecretsave.exe", "D:workelectronAesTest.rar", "1"]

      数组第二个值是文件路径,第三个值是注册表传递过来的参数

    三、使用electron-builder里面的nsis对象,让应用在安装时写入注册表

    1、package.json里面配置:

    "nsis": {
          "oneClick": false,
          "perMachine": true,
          "allowElevation": true,
          "allowToChangeInstallationDirectory": true,
          "createDesktopShortcut": true,
          "runAfterFinish": true,
          "shortcutName": "无忧密存",
          "installerIcon": "./static/icon.ico",
          "uninstallerIcon": "./static/icon.ico",
          "include": "installer.nsh"
        },
    • include 指定要包含 nsis 的脚本,基于内置的nsis脚本进一步扩展,这个对于构建需求严格得安装过程相当有用
    • script 指定自定义使用 nsis 的脚本,完全自己控制nsis 的打包,用于自定义安装程序,默认为build / installer.nsi

      关于include 和 script 到底选择哪一个 ?

      在对个性化安装过程需求并不复杂,只是需要修改一下安装位置,卸载提示等等的简单操作建议使用include配置,如果你需要炫酷的安装过程,建议使用script进行完全自定义。

      我们只是添加两个按钮,使用include就好

    2、编写installer.nsh文件,放在build文件夹下

    !macro customInstall
      WriteRegStr HKCR "CenDC" "URL Protocol" ""
      WriteRegStr HKCR "CenDC" "" "URL:CenDC Protocol Handler"
      WriteRegStr HKCR "*shell密存加密command" "" '"$INSTDIRsecretsave.exe" "%1" "1"'
      WriteRegStr HKCR "*shell密存解密command" "" '"$INSTDIRsecretsave.exe" "%1" "2"'
    !macroend
    !macro customUninstall
      DeleteRegKey HKCR "*shell密存加密"
      DeleteRegKey HKCR "*shell密存解密"
    !macroend

      简单解释脚本的含义,具体了解详情请看下方参考资料:
      !macro 是定义宏
      customInstall会在文件安装后自动调用(electron-builder实现)
      WriteRegStr 是写注册表 如果原来有会覆盖。
      $INSTDIR 是所选的文件安装路径

      HKCR即是注册表目录HKEY_CLASSES_ROOT的缩写。在写value的时候如果要写多个参数,可以用单引号包起来。attr-name不写即为默认

      customUnInstall在卸载阶段将之前写的注册表删除,以免用户卸载了应用之后菜单还在

     四、问题修改

      效果虽然达到了,但是每次右键都会新开一个应用,node服务端口就会占用

    1、解决端口占用问题,实现单例应用的命令行调用:如果应用已经打开的情况下,不打开新窗口

      Electron版本v4.x以上用的是app.requestSingleInstanceLock,2.0用的是app.makeSingleInstance

    const { app } = require('electron')
    let mainWindow = null
      
    const gotTheLock = app.requestSingleInstanceLock() // 拿到单例锁
      
    if (!gotTheLock) { // 如果一个应用二次打开,那么getTheLock为false
      app.quit() // 立即退出二次打开的应用
    } else {
      app.on('second-instance', (event, commandLine, workingDirectory) => { // 一个应用尝试打开第二个实例时触发
        if (mainWindow) {
          if (mainWindow.isMinimized()) mainWindow.restore()
          mainWindow.focus()     
        }
      })
      
      // Create myWindow, load the rest of the app, etc...
      app.on('ready', () => {
          
      })
    }

     端口占用的问题解决了,但是数据无法传递,应用只是聚焦,并没有做任何处理

    2、进程通信修改

      global.sharedObject可以做到数据共享,却没有实质的通信功能;

      ipcMain与ipcRenderer需要渲染进程先发消息,于是选择了主进程用webContents.send发送消息,渲染进程用ipcRenderer监听

      修改后代码如下:

    if (!gotTheLock) {
      app.quit()
    } else {
      app.on('second-instance', (event, commandLine, workingDirectory) => {
        // 当运行第二个实例时,将会聚焦到myWindow这个窗口
        if (mainWindow) {
          if (mainWindow.isMinimized()) mainWindow.restore()
          mainWindow.focus()
          global.sharedObject = {prop1: process.argv}
          mainWindow.webContents.send('getRightPath', process.argv)
          /* dialog.showMessageBox({
            title: 'second',
            message: 'second:' + commandLine + ' workingDirectory' + workingDirectory
          }) */
        } else {
          if (app.isReady()) createWindow()
          global.sharedObject = {prop1: process.argv}
        }
      })
      // mac环境
      app.on('open-url', (event, commandLine, workingDirectory) => {
        // 当运行第二个实例时,将会聚焦到myWindow这个窗口
        if (mainWindow) {
          if (mainWindow.isMinimized()) mainWindow.restore()
          mainWindow.focus()
          global.sharedObject = {prop1: process.argv}
          mainWindow.webContents.send('getRightPath', process.argv)
        } else {
          if (app.isReady()) createWindow()
          global.sharedObject = {prop1: process.argv}
        }
      })
      // 创建 myWindow, 加载应用的其余部分, etc...
      app.on('ready', () => {
        createWindow()
        global.sharedObject = {prop1: process.argv}
      })
    }

      渲染进程vue组件里面改为:

    const ipc = require('electron').ipcRenderer
    methods: {
      dealArgs () {
            let args = remote.getGlobal('sharedObject').prop1
            // console.log("666--:",args)
            let types = ['1','2']
            if (args.length >= 3 && types.includes(args[2])) {
              args[1] = args[1].replace(/\/g, '/')
              this.getArgFile(args)    
            }
          }
     },
    mounted () {
          let _this = this
          this.dealArgs() // 第一次进入时也处理
          ipc.on('getRightPath', function (event, argv) {
            _this.dealArgs()
          })
       } 

    参考资料:

    Electron-vue开发实战7——命令行调用与系统级别右键菜单项的实现

    electron-builder构建的安装包,安装时通过nsis脚本自动导入注册表

    electron 构建打包总结

    Electron 渲染进程之间的通信

  • 相关阅读:
    socket编程技巧(2)发送缓冲区和接收缓冲区的设置时机
    socket编程技巧(1)tcp接收接口(变长数据定长数据)的编写实例
    libnet介绍与分析
    TCP的6大标示符号
    数据帧中常见协议类型
    C语言中offsetof宏的应用
    ip欺骗(原始套接字系列九)
    ARP欺骗(原始套接字系列八)
    包分析(原始套接字七)
    了解Javascript中函数作为对象的魅力
  • 原文地址:https://www.cnblogs.com/goloving/p/13019398.html
Copyright © 2020-2023  润新知