针对clickonce发布后的程序,优化处理省略弹出层

 

 

 

 

 

 

 

 

 

 谷歌插件封装:

1. VSCode新建文件目录

2. 创建manifest.json文件

{
  "version": "1.0", //插件版本
  "manifest_version": 2, //版本号,由google指定为2 ,必须是2
  "name": "插件名称", //插件名称
  "description": "插件描述", //插件描述
  "icons": { //插件图标
    "128": "icons/header_128_128.png",
    "64": "icons/header_64_64.png",
    "48": "icons/header_48_48.png",
    "32": "icons/header_32_32.png",
    "16": "icons/header_16_16.png"
  },
  "background": {
    "persistent": true,
    "scripts": [ "background.js" ]
 },
  "permissions": [ "webRequest", "webRequestBlocking", "nativeMessaging", "http://*/*", "https://*/*" ],
  "update_url": "https://wwww.baidu.com",//插件更新地址
  "browser_action": {
    "default_icon": "icons/header_16_16.png", //插件图标
    "default_popup": "index.html" //点击图标后弹出的html互动文件
  },
  "web_accessible_resources": [ "icons/header_16_16.png" ],
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" //希望能在 Chrome 插件中使用 Vue 放开内容安全策略,才可以使用evel,new Function等函数
}

3. 新增background.js

var nativeHostName = "客户端APPName"; // 需要跟后端客户端一致

// 根据配置文件连接到本地程序
var port = chrome.runtime.connectNative(nativeHostName); 
port.onDisconnect.addListener(() => {
  console.log(
    "连接到客户端服务失败: " + chrome.runtime.lastError.message
  );
  port = null;
});

// 点击url地址链接后进行判断,发现是打开clickonce的程序携带{clickonce:url}的参数发送到客户端,客户端会提前注册到注册表,找到注册表的json文件,再调用json文件配置的客户端地址
chrome.webRequest.onBeforeRequest.addListener(
  function (details) {
    if (details.url.indexOf(".application") != -1) {
      var el = document.createElement("a");
      el.href = details.url;
      if (el.pathname.match(/\.application$/)) {
        chrome.runtime.sendNativeMessage(nativeHostName, {
          clickonce: details.url,
        });
        return { redirectUrl: "javascript:void(0)" };
      }
    }
  },
  { urls: ["http://*/*", "https://*/*"] },
  ["blocking"]
);

// 下载启动exe程序自动执行到注册表,注意这里的plugin.html,其实是一个插件下载页面,进入后自动下载后端exe客户端
chrome.runtime.onInstalled.addListener(function (details) {
  if (details.reason == "install" || details.reason == "update") {
    chrome.tabs.create({ url: chrome.extension.getURL("plugin.html") });
  }
});

4. 新增默认启动页面index.html

<html>
  <head>
    <title>Plugin</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <!--需要引用background后台执行的js文件--> <script type="text/javascript" src="background.js"></script> </head> <body> <h3>插件初始化成功!</h3> </body> </html>

5. 新增plugin.html,

<html>
<head>
<title>Plugin</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script type="text/javascript">
// 自动下载后端服务的插件
  window.onload = function() {
var anchorObj = document.body.children.namedItem('helper-download');
// {"clickonce":"http://域名/winform部署到iis的clickonce的app url地址"}
anchorObj.href = chrome.extension.getURL('/exe/c#封装的注册到注册表地址的一个exe程序.exe');
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
var allowDefault = anchorObj.dispatchEvent(evt);
};
</script>
</head>
<body>
<h3>下载安装插件!</h3>
</body>
</html>



6. c#封装执行程序

internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            string text = NativeClickOnce.OpenStandardStreamIn();
      
            if (!string.IsNullOrEmpty(text))
            {
                if (text.StartsWith("{\"clickonce\":\"") && NativeClickOnce.StartClickOnce(text))
                {
                    NativeClickOnce.OpenStandardStreamOut("{\"result\":\"OK\"");
                }
                return;
            }

            string[] commandLineArgs = Environment.GetCommandLineArgs();
            if (commandLineArgs.Length <= 1)
            {
                Install.Installer();
                return;
            }
            if (commandLineArgs[1].Equals("/Uninstall"))
            {
                Install.Uninstall();
                return;
            }
            Install.Installer();
        }
    }
 public class NativeClickOnce
    {
        public static bool StartClickOnce(string URI_Native)
        {
            string str = URI_Native.Substring("{\"clickonce\":\"".Length, URI_Native.Length - "{\"clickonce\":\"".Length - "\"}".Length);
            new Process
            {
                StartInfo = new ProcessStartInfo("PresentationHost.exe", "-LaunchApplication " + str)
            }.Start();
            return true;
        }

        public static string OpenStandardStreamIn()
        {
            Stream stream = Console.OpenStandardInput();
            byte[] array = new byte[4];
            stream.Read(array, 0, 4);
            int num = BitConverter.ToInt32(array, 0);
            string text = "";
            for (int i = 0; i < num; i++)
            {
                text += (char)stream.ReadByte();
            }
            return text;
        }

        public static void OpenStandardStreamOut(string stringData)
        {
            int length = stringData.Length;
            Stream stream = Console.OpenStandardOutput();
            stream.WriteByte((byte)(length & 255));
            stream.WriteByte((byte)(length >> 8 & 255));
            stream.WriteByte((byte)(length >> 16 & 255));
            stream.WriteByte((byte)(length >> 24 & 255));
            // 成功与否
            Console.Write(stringData);
        }
    }
 public class Install
    {
   private static string GooleExtID
= "这个是插件安装后的ID,跟注册后的json文件里面的要一致"; private static string AppName = "要跟js写一致";//跟js通信 ,必须字母小写,否则会报错 private static string InstallDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Menarva\\Plugin"); private static string jsonInstall = Path.Combine(Install.InstallDir, "plugin.json"); public static void Installer() { try { Directory.CreateDirectory(Install.InstallDir); string text = Path.Combine(Install.InstallDir, Assembly.GetExecutingAssembly().ManifestModule.ScopeName); File.Copy(Assembly.GetExecutingAssembly().Location, text, true); string[] value = new string[] { "{{", " \"name\": \"{0}\",", " \"description\": \"{1}\",", " \"path\": \"{2}\",", " \"type\": \"stdio\",", " \"allowed_origins\": [\"chrome-extension://{3}/\"]", "}}" }; string format = string.Join("\n", value); File.WriteAllText(Install.jsonInstall, string.Format(format, new object[] { AppName, "Plugin for Chrome", text.Replace("\\", "\\\\"), Install.GooleExtID })); Registry.SetValue($"HKEY_CURRENT_USER\\Software\\Google\\Chrome\\NativeMessagingHosts\\{AppName}", null, Install.jsonInstall); string keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + Assembly.GetExecutingAssembly().ManifestModule.ScopeName; Registry.SetValue(keyName, "Comments", "Plugin for Chrome"); Registry.SetValue(keyName, "DisplayName", "Plugin for Chrome"); Registry.SetValue(keyName, "DisplayIcon", text); Registry.SetValue(keyName, "Publisher", "Menarva Ltd"); Registry.SetValue(keyName, "NoModify", 1); Registry.SetValue(keyName, "NoRepair", 1); Registry.SetValue(keyName, "UninstallString", text + " /Uninstall"); MessageBox.Show("Plugin for Chrome successfully!"); } catch (Exception ex) { MessageBox.Show("Plugin Installer error:" + ex.Message); } } public static void Uninstall() { try { Registry.CurrentUser.DeleteSubKeyTree($"Software\\Google\\Chrome\\NativeMessagingHosts\\{AppName}"); Registry.CurrentUser.DeleteSubKeyTree("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + Assembly.GetExecutingAssembly().ManifestModule.ScopeName); File.Delete(Install.jsonInstall); MessageBox.Show("Plugin for Chrome\", \"The plugin was uninstalled successfully!"); ProcessStartInfo startInfo = new ProcessStartInfo { Arguments = string.Format("/C choice /C Y /N /D Y /T 3 & rd /S /Q \"{0}\"", Install.InstallDir), WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, FileName = "cmd.exe" }; Process.Start(startInfo); } catch (Exception ex) { MessageBox.Show("Plugin Uninstall error:"+ex.Message); } } }

7. 打包成一个exe程序

7.1 安装依赖包ILMerge

 7.2 自动生成的就是一个exe,如果依赖了多个dll,需要配置,百度参考ILMerge的其他文档

7.3 将exe拖动到Vue的插件开发文件目录里面

 7.4 安装浏览器插件,点击加载已解压的扩展程序,选择当前Vs Code开发的项目目录地址

 7.5 注意安装后查看扩展程序ID是否跟C#程序的GooleExtID是否一致,必须要一致才可以,否则会报错,这里程序会下载c#写的exe程序,需要点击注册,注册成功后即可使用

 7.6 也可以使用打包的方式进行,选择项目目录,进行打包,打包后会生成2个文件,一个*.crx文件,一个*.pem文件,*.crx文件可以直接拖动到浏览器进行安装,注意安装之前需要开启开发者模式

 

7.7 *.crx安装后会提示如下,以及ID不可控,这里需要注意。暂时没有找到解决办法

 

7.8 然后就可以通过a标签点击跳转到click once部署的winform、wpf程序进行直接打开exe程序

let herf = `${url}/APPClient/*****.application?携带参数传递到winfrom/wpf`;
window.open(herf, '_parent');
// _blank 、_self 、_parent、_top
<a href="clickOnce部署的APP地址/参数" target="_parent">打开xxx系统</a>

 7.9 安装后可以查看注册表地址

地址:计算机\HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\你的AppName

点击右侧默认的属性,会显示存储的json位置

7.10 打开json位置如下:

地址:C:\Users\29561\AppData\Local\Menarva

该位置下面有你的exe程序,一个json文件

7.11 json文件内容如下

{
  "name": "你的AppName",
  "description": "Plugin for Chrome",
  "path": "C:\\Users\\29561\\AppData\\Local\\Menarva\\Plugin\\xxxPlugin.exe",
  "type": "stdio",
  "allowed_origins": ["chrome-extension://你的插件ID,必须要跟浏览器安装后看到的扩展程序的ID一致/"]
}

 

posted @ 2023-07-14 10:48  彪悍的代码不需要注释  阅读(70)  评论(0编辑  收藏  举报
39
0