C# Winform插件开发笔记

  1. Process调起应用程序
    • Arguments传参(Windows服务无法使用以下方式发起调用,因为不属于同一session,需要引入底层类库,模拟用户进程以启动新程序)
      1                 Process process = new Process();
      2                 process.EnableRaisingEvents = true;
      3                 process.Exited += designerExitedHandler;
      4                 process.StartInfo = new ProcessStartInfo
      5                 {
      6                     FileName = "\"" + appPath + "\"",
      7                     Arguments = string.Format("/F=\"{0}\"", filePath)
      8                 };
      View Code
  2. Main函数参数传入:为字符串数组,调用时通过一个空格分隔的字符串传入(调试时可通过项目右键->属性->Debug-> Start Options配置)
  3. WebClient应改用HttpClient
    • HttpClient旨在实例化一次,并在应用程序的整个生命周期内重新使用。 实例化每个请求的 HttpClient 类将耗尽大量负载下可用的套接字数。 这将导致 SocketException 错误。
    • https://docs.microsoft.com/zh-cn/dotnet/api/system.net.http.httpclient?view=net-6.0
    • https://docs.microsoft.com/zh-cn/dotnet/api/system.net.webclient?view=net-6.0
  4. 本地化
    1. 新建.resx文件,如PluginMessages.resx、PluginMessages.zh-CN.resx,在其中配置词条译文即可
    2. 通过本地化文件.词条名引用,如 PluginMessages.Error
      throw new ValidationException(PluginMessages.ArgumentsError);
    3. 应用程序会根据当前Thread.CurrentThread.CurrentUICulture自动选择译文
    4. 也可通过代码更改 
      Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
    5. 隐藏Form窗口
      protected override CreateParams CreateParams
              {
                  get
                  {
                      const int WS_EX_APPWINDOW = 0x40000;
                      const int WS_EX_TOOLWINDOW = 0x80;
      
                      CreateParams cp = base.CreateParams;
      
                      cp.ExStyle &= (~WS_EX_APPWINDOW);    // 不显示在TaskBar
                      cp.ExStyle |= WS_EX_TOOLWINDOW;      // 不显示在Alt+Tab
      
                      return cp;
                  }
              }
      
              private void FrmEditTemplate_Load(object sender, EventArgs eventArgs)
              {
                  //窗体最小化显示
                  this.WindowState = FormWindowState.Minimized;
      
                  //不显示在任务栏中
                  this.ShowInTaskbar = false;
         }
  5. 操作完成后自动关闭应用程序
    Environment.Exit(Environment.ExitCode);

     https://www.jb51.net/article/58816.htm

  6. multipart/form 方式提交数据

     1         /// <summary>
     2         /// 使用multipart/form-data方式上传文件及提交其他数据
     3         /// </summary>
     4         /// <param name="headers">请求头参数</param>
     5         /// <param name="nameValueCollection">键值对参数</param>
     6         /// <param name="fileCollection">文件参数:参数名,文件路径</param>
     7         /// <returns>接口返回结果</returns>
     8         public static string UploadMultipartFormData(string url, string httpMethod, Dictionary<string, string> headers, NameValueCollection nameValueCollection, NameValueCollection fileCollection)
     9         {
    10             var requestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), url);
    11             foreach (var item in headers)
    12             {
    13                 requestMessage.Headers.Add(item.Key, item.Value);
    14             }
    15 
    16             using (var content = new MultipartFormDataContent())
    17             {
    18                 // 键值对参数
    19                 string[] allKeys = nameValueCollection.AllKeys;
    20                 foreach (string key in allKeys)
    21                 {
    22                     var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(nameValueCollection[key]));
    23                     dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    24                     {
    25                         Name = key
    26                     };
    27                     content.Add(dataContent);
    28                 }
    29 
    30                 //处理文件内容
    31                 string[] fileKeys = fileCollection.AllKeys;
    32                 foreach (string key in fileKeys)
    33                 {
    34                     byte[] bmpBytes = File.ReadAllBytes(fileCollection[key]);
    35                     var fileContent = new ByteArrayContent(bmpBytes);//填充文件字节
    36                     fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    37                     {
    38                         Name = key,
    39                         FileName = Path.GetFileName(fileCollection[key])
    40                     };
    41                     content.Add(fileContent);
    42                 }
    43 
    44                 using (var httpClient = new HttpClient())
    45                 {
    46                     var httpResponse = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None).Result;
    47 
    48                     var statusCode = httpResponse.StatusCode;
    49                     var responseContent = httpResponse.Content;
    50                     string data = responseContent.ReadAsStringAsync().Result;
    51 
    52                     if (statusCode != System.Net.HttpStatusCode.OK)
    53                     {
    54                         throw new ValidationException($"{PluginMessages.UploadFailed}: HttpStatusCode={statusCode}, {data}");
    55                     }
    56                     return data;//返回操作结果
    57                 }
    58             }
    59         }
    View Code
  7. 网页调用本地应用
    •   在注册表配置本地应用路径(URL Protocol),a标签或window.open传入注册表配置即可打开,参数写在URL Protocol后面,只能写一个,自定义分隔符解析参数,程序需要UrlDecode参数,网页发布后由于浏览器安全机制,可能每次都会弹是否打开的询问框,如果是https,会对一个复选框,勾选后以后不会弹出询问框。
  8. 获取正在运行的应用
  9. 获取正在运行的应用

           

 1             Process[] processes = Process.GetProcesses();
 2             _log.Info("processes.Length = " + processes.Length);
 3             List<string> listProc = new List<string>();
 4             foreach (Process p in processes)
 5             {
 6                 if (p.MainWindowHandle.ToInt32() > 0)
 7                 {
 8                     if (p.MainWindowTitle.StartsWith("BarTender"))
 9                     {
10                         // 存在已运行的bartender进程时无法打开文档,需要先关闭
11                         throw new ValidationException(PluginMessages.BartendIsRunning);
12                     }
13                     _log.Info("p.MainWindowTitle = " + p.MainWindowTitle);
14                 }
15             }
  1. 其它类
    1. BackgroundWorker 在单独的线程上执行操作,可以更新Form内控件属性,用BeginInvoke会报跨线程错误。https://docs.microsoft.com/zh-cn/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7
    2. ApplicationSettingsBase 作为派生具体包装类以实现 Window 窗体应用程序中的应用程序设置功能的基类。https://docs.microsoft.com/zh-cn/dotnet/api/system.configuration.applicationsettingsbase?view=dotnet-plat-ext-6.0
    3. ClickOnce发布程序,自动检查更新并安装 https://blog.csdn.net/tcjiaan/article/details/12285533
    4. Mutex:互斥锁,可保证只有一个进程实例运行
    5. SerialPort:串口读写数据
  2. 一些坑

    1. Process.GetProcessesByName可能取不到正在运行的进程
    2. HttpWebRequest.Create(url).GetResponse() 不支持HTTPS,需要额外设置
    3. Bartender提供的Printers获取到的默认机可能会错误
  string _defaultPrinter = new PrintDocument().PrinterSettings.PrinterName;
// 增加Https支持
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| (SecurityProtocolType)0x300 //Tls11
| (SecurityProtocolType)0xC00; //Tls12

 

posted @ 2022-04-28 19:45  冰山雪梨  阅读(617)  评论(0编辑  收藏  举报