关于修改注册表信息,设置软件为默认应用
前言
实现图片鼠标右键增加自定义可执行软件打开方式,增加图片查看器等功能,以及修改电脑的默认应用程序。
涉及修改打包应用程序.bat文件,修改电脑注册表信息
一、实现鼠标右键增加自定义应用
riteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "" "通过${PRODUCT_NAME}打开"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "icon" "$INSTDIR\logo.ico"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "MultiSelectModel" "Single"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}\command" "" '"$INSTDIR\${EXE_NAME}" "%1" "Preview"'
释义:在 Windows 中使用 NSIS(Nullsoft Scriptable Install System)脚本语言写的注册表操作。
WriteRegStr HKCR “SystemFileAssociations\image\shell${URL_NAME}” “”
“通过 ${PRODUCT_NAME}打开”
这行代码将注册表项 HKCR\SystemFileAssociations\image\shell${URL_NAME} 下的默认值(空字符串)设置为 “通过${PRODUCT_NAME}打开”。这通常用于定义文件关联的操作。
2.
WriteRegStr HKCR “SystemFileAssociations\image\shell${URL_NAME}”
“icon” “$INSTDIR\logo.ico”
这行代码将注册表项 HKCR\SystemFileAssociations\image\shell${URL_NAME} 下的键名为 “icon” 的值设置为 $INSTDIR\logo.ico,表示使用 $INSTDIR\logo.ico 文件作为关联文件的图标。
3.
WriteRegStr HKCR “SystemFileAssociations\image\shell${URL_NAME}”
“MultiSelectModel” “Single”
这行代码将注册表项 HKCR\SystemFileAssociations\image\shell${URL_NAME} 下的键名为 “MultiSelectModel” 的值设置为 “Single”,指定文件的选择模式为单选模式。
4.
WriteRegStr HKCR
“SystemFileAssociations\image\shell${URL_NAME}\command” “”
‘“$INSTDIR${EXE_NAME}” “%1” "Preview’"
这行代码将注册表项 HKCR\SystemFileAssociations\image\shell${URL_NAME}\command 下的默认值(空字符串)设置为 ‘“$INSTDIR${EXE_NAME}” “%1” “Preview”’。这通常用于定义打开文件的命令,其中 $INSTDIR${EXE_NAME} 表示安装目录下的可执行文件,“%1” 表示要打开的文件路径参数,“Preview” 是传递给可执行文件的参数。
提示:总的来说,这些代码片段用于配置文件关联的操作、图标显示、选择模式以及打开文件的命令,以便在系统中正确地处理特定类型的文件。:
示例
1. 在打包执行文件中添加相应变量(在package.bat执行文件中添加)
:: 安装NSI中所需参数
@set PRODUCT_NAME=图片查看器
@set PRODUCT_VERSION=%GIT_TAG_NAME:~1%
@set PRODUCT_PUBLISHER=软甲归属
@set EXE_NAME=PhotoEditor.exe
@set INSTALL_DIR=MyApp
@set URL_NAME=PhotoEditor
@set PRODUCT_WEB_SITE=https://www.myappcom
SET MAINEXE_FILENAME=PhotoEditor
2. 在nsi打包文件中加入执行命令(package_HuDunPhotoEA.nsi)
Section -Post
WriteUninstaller "$INSTDIR\uninst.ep"
WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\${EXE_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\logo.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "" "通过${PRODUCT_NAME}打开"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "icon" "$INSTDIR\logo.ico"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}" "MultiSelectModel" "Single"
WriteRegStr HKCR "SystemFileAssociations\image\shell\${URL_NAME}\command" "" '"$INSTDIR\${EXE_NAME}" "%1" "Preview"'
SectionEnd
3.在electron的主窗口main.js中增加查看器子窗口
const { app,BrowserWindow,Menu,globalShortcut,screen,protocol,Tray} = require('electron')
let win = null
let tray = null
let winURL = null
let childWin = null
let group = []
let ishide = false;
let index = 0
let process = require('process')
let userInfo = {}
// 添加数据
function addRegData(path, type) {
if (type == "Preview") global.previewPath.push(path);
else {
global.imgPath[type].push(path);
// 将其他的清空
for (let key in global.imgPath) {
if (key != type) global.imgPath[key] = [];
}
global.imgType = type;
}
}
/**
* 查看器子窗口
* @childWin 存在有多个子窗口时
* @group 一个数组对象,[childWin1,childWin2...]
* @Preview 子窗口的显示路径url,此处的命名Preview应与打包配置文件中传递给可执行文件的参数一致
*/
function openChildWindow() {
childWin ={
id:index,
obj:null,
}
let newWinConfig = JSON.parse(JSON.stringify(winConfig));
newWinConfig.title = "图片助手——查看";
// newWinConfig.parent = win; // 还是平级的吧
newWinConfig.resizable = true; // 窗口可以拖动
childWin.obj = new BrowserWindow(newWinConfig);
remote.enable(childWin.obj.webContents);
if (/xunjietupian/.test(winURL)) {//正式环境
chooseDomain([
"photo-pc.aaa.com",
"photo-pc.aaa1.com",//是否有多个域名
]).then((res) => {
childWin.obj.loadURL(
"https://" +
res +
"/5.4.0.0/?ran=" +
new Date().getTime() +
"#/" +
"Preview"
);
});
} else {
if (/9900/.test(winURL)) {//本地环境
childWin.obj.loadURL(winURL + "#/" + "Preview"); // hash路由
} else {
console.log(
winURL + "/5.4.0.0/?ran=" + new Date().getTime() + "#/" + "Preview"
);
childWin.obj.loadURL(
winURL + "/5.4.0.0/?ran=" + new Date().getTime() + "#/" + "Preview"
); // hash路由
}
}
// // 在加载页面时,渲染进程第一次完成绘制时
childWin.obj.once("ready-to-show", () => {
console.log("显示");
setTimeout(() => {
childWin.obj.show();
childWin.obj.focus();
}, 350);
});
//设置调试环境
globalShortcut.register("Alt+F11", () => {
console.log(childWin,'====childWin-------');
childWin.obj.webContents.openDevTools();
});
childWin.obj.on("closed", () => {
childWin.obj = null;
});
childWin.obj.webContents.on("did-finish-load", () => {
childWin.obj.webContents.send("refreshfilearg",global.previewPath[index],index);
//子进程与主进程同步所需要的信息
childWin.obj.webContents.send("dataChanged",userInfo);
index++
});
group.push(childWin)
console.log(group,'=======group');
}
// 主窗口托盘处理
function setTray() {
const trayMenuTemplate = [
{
label: "打开窗口",
click: () => {
win.show();
if (tray) {
tray.destroy();
tray = null;
ishide=false;
}
},
},
{
label: "退出",
click: () => {
win.destroy();
win = null;
},
},
];
// 创建托盘实例
if (tray == null) tray = new Tray(ICO_PATH);
// 图标的上下文菜单
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);
// 隐藏主窗口
win.hide();
// 设置托盘悬浮提示
tray.setToolTip("图片助手");
// 设置托盘菜单
tray.setContextMenu(contextMenu);
// 单机托盘小图标显示应用
tray.on("click", function () {
// 显示主程序
win.show();
ishide=false;
// 关闭托盘显示
if (tray) {
tray.destroy();
tray = null;
}
});
}
// 创建浏览器窗口
function createWindow() {
global.previewPath = []; //预览
global.imgType = ""; // 会记录最近的一次操作
if (process.argv && process.argv[2]) {
// 储存数据,用对象方式,多张图片。软件第一次运行,可能还没有实例完。
addRegData(process.argv[1], process.argv[2]);
// 开始加载子窗口
if (process.argv[2] == "Preview") {
ishide = true;
openChildWindow();
}
}
getSdkPath();
win = win != null ? win.show() : new BrowserWindow({
width: 1170,
height: 726,
minWidth: 1024,
minHeight: 580,
show: false,
resizable: true,
maximizable: true,
fullscreenable: true,
icon: ICO_PATH,
center: true,
titleBarStyle: "hidden",
title: "图片编辑助手",
// transparent:true,
//MAC_OS
simpleFullscreen: true,
//no border
frame: false,
webPreferences: {
webSecurity: false,//设置无法读取到本地文件图片问题,解决electron的跨域问题
contextIsolation: false,
nodeIntegration: true,
enableRemoteModule: true,
webviewTag: true,
}
})
}
4.在vue文件中加入需要展示的页面,接受主进程传递的消息
[(vue中src–>views–>Preview)]
created() {
window.asd = this;
ipcRenderer.on("refreshfilearg", (e, data,index) => {
this.imgPreviewId = index
console.log("开始显示");
ipcRenderer.send("showChildWeb");
// 处理data中的图片信息
this.imgInit(data);
});
},
}
以上就可以实现在图片上点击鼠标右键打开软件了
二、将电脑的默认软件修改为自己的软件,修改注册表信息
方法1.使用注册表文件(注册表文件需自己编写)
1.创建一个regFolder文件夹,其中包括open.reg文件和delete.reg文件
open.reg
代码如下(示例):
Windows Registry Editor Version 5.00
//将.pdf格式文件的打开方式修改为PhotoEditor的应用,用于关联
[HKEY_CLASSES_ROOT\.pdf]
@="PhotoEditor"
//添加默认应用的打开路径
[HKEY_CLASSES_ROOT\PhotoEditor\shell\open\command]
@="${install} \"%1\" \"Preview\""
//删除原有的默认应用的设置参数
[-HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.pdf\UserChoice]
//增加的默认应用的设置参数
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.pdf\UserChoice]
"Hash"="mRngFltqE1c="
"ProgId"="PhotoEditor"
//系统将会删除注册表中名为 MSEdgePDF 的项及其下的所有子项,从而清除相关的注册表配置信息。此句可不要
[-HKEY_CLASSES_ROOT\MSEdgePDF]
- ${install}:为应用软件的安装路径,应动态获取。例如:
[HKEY_CLASSES_ROOT\PhotoEditor\shell\open\command]
@=“C:\ProgramData\HuDunPhotoEA\PhotoEditor.exe “%1” “Preview””
- “ProgId”:为应用的名称
- HKEY_CLASSES_ROOT 是注册表中的一个根键,包含了文件关联和对象类别的信息。
delete.reg
代码如下(示例):
Windows Registry Editor Version 5.00
//取消注册表的文件关联
[-HKEY_CLASSES_ROOT\SystemFileAssociations\.pdf\shell]
调用方式
//roamingPath为存放注册表文件的路径
function readReg(fileName){
let regFile = path.join(roamingPath, "../regFolder", fileName);
console.log("文件路径----", regFile);
return new Promise((resolve, reject) => {
fs.readFile(regFile, (werr, data) => {
if (werr) {
return reject(werr);
}
let regData = iconv.decode(data, "gbk");
if (regData.indexOf("${install}") > -1 || regData.indexOf("${install2}") > -1) {
regData = regData.replaceAll(
"${install}",
path.join(window.process.argv[0]).replace(/[\/\\]/g, "\\\\")
);
regData = regData.replaceAll(
"${install2}",
path.join(window.process.argv[0], "../icon").replace(/[\/\\]/g, "\\\\")
);
regData = iconv.encode(regData, "gbk");
fs.writeFile(regFile, regData, (err) => {
if (err) {
reject(err);
}
exec(`regedit /s "${regFile}"`, (err, stdout, stderr) => {
if (err || stderr) {
console.error(err);
resolve(false);
} else {
resolve(true);
}
});
});
} else {
exec(`regedit /s "${regFile}"`, (err, stdout, stderr) => {
if (err || stderr) {
console.error(err);
resolve(false);
} else {
resolve(true);
}
});
}
});
});
}
readReg("open.reg");
方法2.调用c++提供的dll
需要有对应的dll可调用。调用方式根据所提供的方式来
代码如下(示例):
const dllPath = path.join(mainPath, '../dll/SetDefaultTool.dll')
const winDll = new ffi.Library(dllPath,{
WriteUserChoice: [ref.types.bool, [refArray(ref.types.uint16), refArray(ref.types.uint16)]],
DeleteUserChoice: [ref.types.bool, [refArray(ref.types.uint16)]],
})
/**
* 写入注册表信息方法
* @param {*} key 修改的格式
* @param {*} value 需要修改成的软件名称
*/
writeUserChoice = (key, value='PhotoEditor') => {
// const keyBuffer = Buffer.from(key)
// const valueBuffer = Buffer.from(value)
// const res = winDll.WriteUserChoice(keyBuffer, valueBuffer)
const keyCodes = new refArray(ref.types.uint16)(256)
for(let i=0; i< key.length; i++) {
keyCodes[i] = key.charCodeAt(i)
}
const valueCodes = new refArray(ref.types.uint16)(256)
for(let i=0; i< value.length; i++) {
valueCodes[i] = value.charCodeAt(i)
}
const res = winDll.WriteUserChoice(keyCodes.buffer, valueCodes.buffer)
//返回true or false
}
writeUserChoice('.png')
问题
提示:这里对文章进行总结:
1.调用成功后,双击图片并未使用设置的软件打开图片
以上两种方式都存在,虽然调用成功了,但是在修改时系统会弹出提示弹窗
原因:其实我们已经修改成功了,但是又被系统改回去了,导致失败。
有些常用格式,有其它多个应用抢占的时候,电脑系统就是会自动把设置的给你删掉,并不是所有格式都能一次性成功修改,这个时候可以尝试在修改时多次调用执行修改的命令。
2.注册表信息已经修改成功,且在系统注册表中也可查看到设置的对应信息,但是双击图片时又被修改为之前的默认应用了
- 首先在文件执行成功后,打开注册表查看是否修改成功
但是在双击图片打开这里的值就自动修改为之前的默认应用了
原因:未关联注册表信息。
前面设置的这段代码就是在关联注册表,仅仅是修改注册表的UserChoice的配置修改并不能将应用设置未默认的。在默认应用的选择列表中并不会出现设置的应用
//将.pdf格式文件的打开方式修改为PhotoEditor的应用,用于关联
[HKEY_CLASSES_ROOT.pdf]
@=“PhotoEditor”
//添加默认应用的打开路径
[HKEY_CLASSES_ROOT\PhotoEditor\shell\open\command]
@=“${install} “%1” “Preview””