安木生 - C#
type: channel
link: https://www.anmusheng.com/index.php/category/csharp/
items: winform窗体中使用WebBrowser嵌入网页
items: C#文件服务器
items: exe程序嵌入Winform窗体
items: WinForm启动和停止进程
items: WinForm程序不在任务栏显示
items: WinForm窗体及其控件自适应各种屏幕分辨率
items: C#设置WebBrowser默认的IE内核
items: BCrypt算法的C#实现
items: winform中TreeView透明背景
items: c#中如何跨线程调用windows窗体控件

winform窗体中使用WebBrowser嵌入网页
type: item
date: 2020-07-14T03:37:00+00:00
description: WebBrowser可以使用WebBrowser控件向Windows窗体客户端应用程序添加现有的动态的Web应用程序。使用WebBrowser控件，可以通过ObjectForScripting和Document属性在客户端应用程序代码和网页脚本代码之间实现双向通信。此外，可以对WebBrowser控件进行配置，使Web控件可以与应用程序窗体上的其他控件进行无缝整合，从而隐藏其HTML实现。若要使控件无缝整合，请对所显示页的格式进行设置，使其背景颜色和视觉样式与窗体的其余部分匹配，然后使用AllowWebBrowserDrop、 IsWebBrowserContextMenuEnabled和WebBrowserShortcutsEnabled属性禁用标准浏览器功能。webBrowser1.AllowWebBrowserDrop = false;//将 WebBrowser 控件的 AllowWebBrowserDrop 属性设置为 false，以防止 WebBrowser 控件打开拖放到其上的文件。 webBrowser1.IsWebBrowserContextMenuEnabled = false;//将该控件的 IsWebBrowserContextMenuEnabled 属性设置为 false，以防止 WebBrowser 控件在用户右击它时显示其快捷菜单. webBrowser1.WebBrowserShortcutsEnabled = false;//将该控件的 WebBrowserShortcutsEnabled 属性设置为 false，以防止 WebBrowser 控件响应快捷键。 webBrowser1.ScriptErrorsSuppressed=true;//将该控件的 ScriptErrorsSuppressed 属性设置为 true，以防止 WebBrowser 控件显示脚本代码问题的错误信息。WebBrowser不单单只做一个浏览器的功能吧，既然是winform程序，那么就牵涉到网页的程序(主要是javascript)和winform本身的程序怎样交互呢？一些Javascript无法实现的功能，可以通过javascript调用Winform里的方法去完成。1.在窗体的构造函数或者Load事件处理程序中设置ObjectForScripting属性：下面代码将窗体类自身用于脚本对象。(组件对象模型(COM)必须能够访问脚本对象,若要使窗体对 COM 可见，请将 ComVisibleAttribute 属性添加到窗体类中)webBrowser1.ObjectForScripting = this;在窗体类自身设置Attribute[PermissionSet(SecurityAction.Demand, Name="FullTrust")] [System.Runtime.InteropServices.ComVisibleAttribute(true)] public class Form1 : Form {}2.在应用程序中实现脚本代码将要调用的winform的公共属性和方法。public string InvokeFormMethod(string message) { MessageBox.Show(message,"Client Code") return "Charles2008" }3.在脚本代码中使用window.external对象访问指定对象的公共属性和方法。 4.在脚本文件中添加JavaScript函数(winform程序将要调用的). 5.使用WebBrowser的Document 属性从客户端应用程序代码访问脚本代码。this.webBrowser1.Document.InvokeScript("msgalert", new string[] { "Called Javascript code" });下面是一个完整的实例：[PermissionSet(SecurityAction.Demand, Name = "FullTrust")] [System.Runtime.InteropServices.ComVisibleAttribute(true)] public partial class Main : Form { public Main() { InitializeComponent(); } private void button4_Click(object sender, EventArgs e) { this.webBrowser1.Navigate(this.textBox1.Text); this.webBrowser1.ObjectForScripting = …

C#文件服务器
type: item
date: 2019-11-03T06:48:00+00:00
description: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; namespace ClassLibrary { /// /// 文件传输服务器 /// public class FileTransferServer { /* 服务器接收文件Socket */ private static Socket ServerSocket; /* 文件根目录 */ private static string ServerRoot; /// /// 初始化服务 /// /// xml配置文件 public static void Init(string config) { /* 加载配置文件 */ XmlDocument xml = new XmlDocument(); //xml.Load(Path.Combine(Environment.CurrentDirectory, "config/tcp.xml")); xml.Load(config); XmlNode Config = xml.SelectSingleNode("Config/FileServer"); IPAddress ListenIP = IPAddress.Parse(Config.Attributes["ListenIP"].Value); int ListenPort = Convert.ToInt32(Config.Attributes["ListenPort"].Value); ServerRoot = Environment.CurrentDirectory; // 默认当前目录 /* 开始监听 */ ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ServerSocket.Bind(new IPEndPoint(ListenIP, ListenPort)); //绑定IP地址：端口 ServerSocket.Listen(10); //设定最多10个排队连接请求 Thread t = new Thread(ListenClientConnect); t.Start(); } private static void ListenClientConnect() { while (true) { if (ServerSocket != null) { try { Socket client = ServerSocket.Accept(); Thread th = new Thread(Handle); th.Start(client); } catch { break; } } } } private static void Handle(Object clientSocket) { Socket client = clientSocket as Socket; // 获取头部协议 string header = ReceiveHeader(client); Console.WriteLine(string.Format("{0} 请求 {1}",client.RemoteEndPoint.ToString() ,header)); // TODO 添加其它协议 switch (header.Substring(0, 3)) { case "PUT": string filename = header.Substring(4); PutFile(client, filename); break; case "GET": string fullPath = header.Substring(4); GetFile(client, fullPath); break; default: Console.WriteLine("We can not suppose this"); client.Close(); break; } } /// /// 接收远程文件 /// /// /// public static void PutFile(Socket client, string filename) { /* 创建一个新文件 */ string extension =…

exe程序嵌入Winform窗体
type: item
date: 2019-10-31T05:57:00+00:00
description: ExeEmbedForm类/// /// 将外部exe嵌入至winform中 /// public class ExeEmbedForm { EventHandler appIdleEvent = null; Control ParentCon = null; string strGUID = ""; public ExeEmbedForm(Control C, string Titlestr) { appIdleEvent = new EventHandler(Application_Idle); ParentCon = C; strGUID = Titlestr; } /// /// 将属性AppFilename指向的应用程序打开并嵌入此容器 /// public IntPtr Start(string FileNameStr) { if (m_AppProcess != null) { Stop(); } try { ProcessStartInfo info = new ProcessStartInfo(FileNameStr); info.UseShellExecute = true; info.WindowStyle = ProcessWindowStyle.Minimized; m_AppProcess = System.Diagnostics.Process.Start(info); m_AppProcess.WaitForInputIdle(); Application.Idle += appIdleEvent; } catch { if (m_AppProcess != null) { if (!m_AppProcess.HasExited) m_AppProcess.Kill(); m_AppProcess = null; } } return m_AppProcess.Handle; } /// /// 确保应用程序嵌入此容器 /// /// /// void Application_Idle(object sender, EventArgs e) { if (this.m_AppProcess == null || this.m_AppProcess.HasExited) { this.m_AppProcess = null; Application.Idle -= appIdleEvent; return; } while (m_AppProcess.MainWindowHandle == IntPtr.Zero) { Thread.Sleep(100); m_AppProcess.Refresh(); } Application.Idle -= appIdleEvent; EmbedProcess(m_AppProcess, ParentCon); } /// /// 应用程序结束运行时要清除这里的标识 /// /// /// void m_AppProcess_Exited(object sender, EventArgs e) { m_AppProcess = null; } /// /// 将属性AppFilename指向的应用程序关闭 /// public void Stop() { if (m_AppProcess != null)// && m_AppProcess.MainWindowHandle != IntPtr.Zero) { try { if (!m_AppProcess.HasExited) m_AppProcess.Kill(); } catch (Exception) { } m_AppProcess = null; } } #region 属性 /// /// application process /// Process m_AppProcess = null; /// /// 标识内嵌程序是否已经启动 /// public bool IsStarted { get { return (this.m_AppProcess != null); } } #endregion 属性 #region Win32 API [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] private static extern long GetWindowThreadProce…

WinForm启动和停止进程
type: item
date: 2019-10-31T03:43:00+00:00
description: 启动进程System.Diagnostics.Process.Start("Client.exe");查看进程Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension("Client.exe")); foreach (Process process in processes) { // 输出每个进程的进程号、名称、占用的物理内存、开始的时间和文件名 Console.WriteLine(process.ProcessName); Console.WriteLine(string.Format("{0} KB",process.PrivateMemorySize64/1024.0f)); Console.WriteLine(string.Format("{0}",process.StartTime),); Console.WriteLine(process.MainModule.FileName); }停止进程Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension("Client.exe")); foreach (Process process in processes) { process.Kill(); }

WinForm程序不在任务栏显示
type: item
date: 2019-10-29T03:49:00+00:00
description: 设置ShowInTaskbar属性值this.ShowInTaskbar =false

WinForm窗体及其控件自适应各种屏幕分辨率
type: item
date: 2019-10-22T09:03:00+00:00
description: 背景我们自己编写程序的界面，会遇到各种屏幕分辨率，只有自适应才能显的美观。实际上，做到这点也很简单，就是首先记录窗体和它上面控件的初始位置和大小，当窗体改变比例时，其控件的位置和大小也按此比例变化即可。（因为窗体上控件的位置和大小是相对于自己所在的窗体的。）使用方法声明自适应辅助类实例为窗体添加Load事件，并在其方法Form\_Load中，调用自适应辅助类方法，记录窗体和其控件初始位置和大小为窗体添加SizeChanged事件，并在其方法Form\_SizeChanged中，调用自适应辅助类的自适应方法，完成自适应完整代码自适应窗体public partial class Form1 : Form { // 声明自适应辅助类实例 AutoSizeFormHelper asf = new AutoSizeFormHelper(); public Form1() { InitializeComponent(); } // 为窗体添加Load事件，并在其方法Form1_Load中，调用自适应辅助类方法，记录窗体和其控件的初始位置和大小 private void Form1_Load(object sender, EventArgs e) { asf.ControlInitializeSize(this); } // 为窗体添加SizeChanged事件，并在其方法Form1_SizeChanged中，调用自适应辅助类的自适应方法，完成自适应 private void Form1_SizeChanged(object sender, EventArgs e) { asf.ControlAutoSize(this); } }自适应辅助类/// /// 自适应窗体辅助类 /// public class AutoSizeFormHelper { // 窗体和其控件的初始位置和大小。 public class ControlRect { public int Left; public int Top; public int Width; public int Height; public ControlRect(int l, int t, int w, int h) { Left = l; Top = t; Width = w; Height = h; } } // 当前控件的位置和大小 public ConditionalWeakTable<Control, ControlRect> oldControls = new ConditionalWeakTable<Control, ControlRect>(); // 当前的窗体位置和大小 public ControlRect formRect; // 记录窗体和其控件的初始位置和大小 public void ControlInitializeSize(Form mForm) { // 窗体自身位置 this.formRect = new ControlRect(mForm.Left, mForm.Top, mForm.Width, mForm.Height); foreach (Control c in mForm.Controls) { ControlRect controlRect = new ControlRect(c.Left, c.Top, c.Width, c.Height); oldControls.Add(c, controlRect); } //记录完控件的初始位置和大小后，最大化 mForm.WindowState = System.Windows.Forms.FormWindowState.Maximized; } // 控件自适应大小, public void ControlAutoSize(Form mForm) { // 缩放比例 float wScale = (float)mForm.Width / (float)formRect.Width; float hScale = (float)mForm.Height / (float)formRect.Height; ControlRect data; foreach (Control c in mForm.Controls) { if (oldControls.TryGetValue(c, out data)) { c.Left = (int)((data.Left) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体，所以只需成比例 c.Top = (int)((data.Top) * hScale); c.Width = (int)(data.Width * wScale); c.Hei…

C#设置WebBrowser默认的IE内核
type: item
date: 2019-10-04T02:23:00+00:00
description: 通常情况下，直接调用WebBrowser控件的时候默认是IE7内核，实在是不美观。using Microsoft.Win32; using System; using System.ComponentModel; namespace ClassLibrary { /// /// 设置Webbrowser控件所用IE内核版本 /// public class WebBrowserHelper { /// 修改注册表信息来兼容当前程序 /// /// public static void SetWebBrowserFeatures(int ieVersion) { // Win8及以上，默认浏览器IE10及以上 OperatingSystem os = Environment.OSVersion; if(os.Version.Major > 6 || os.Version.Major == 6 && os.Version.Minor > 1) { return; } // don't change the registry if running in-proc inside Visual Studio if (LicenseManager.UsageMode != LicenseUsageMode.Runtime) return; //获取程序及名称 string appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); //得到浏览器的模式的值 UInt32 ieMode = GeoEmulationModee(ieVersion); string featureControlRegKey = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\"; //设置浏览器对应用程序（appName）以什么模式（ieMode）运行 Registry.SetValue(featureControlRegKey + "FEATURE_BROWSER_EMULATION", appName, ieMode, RegistryValueKind.DWord); // enable the features which are "On" for the full Internet Explorer browser Registry.SetValue(featureControlRegKey + "FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION", appName, 1, RegistryValueKind.DWord); //Registry.SetValue(featureControlRegKey + "FEATURE_AJAX_CONNECTIONEVENTS", appName, 1, RegistryValueKind.DWord); //Registry.SetValue(featureControlRegKey + "FEATURE_GPU_RENDERING", appName, 1, RegistryValueKind.DWord); //Registry.SetValue(featureControlRegKey + "FEATURE_WEBOC_DOCUMENT_ZOOM", appName, 1, RegistryValueKind.DWord); //Registry.SetValue(featureControlRegKey + "FEATURE_NINPUT_LEGACYMODE", appName, 0, RegistryValueKind.DWord); } /// /// 获取浏览器的版本 /// /// <returns></returns> public static int GetBrowserVersion() { int browserVersion = 0; using (RegistryKey ieKey = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\Microsoft\Internet Explorer", RegistryKeyPermissionCheck.ReadSubTree, System.Security.AccessControl.RegistryRights.QueryValues)) { object version = ieKey.GetVal…

BCrypt算法的C#实现
type: item
date: 2019-09-29T07:33:00+00:00
description: using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Serialization; using System.Security.Cryptography; using System.Text; // // Copyright (c) 2006 Damien Miller <djm@mindrot.org> // Copyright (c) 2013 Ryan D. Emerle // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // namespace: ClassLibrary namespace ClassLibrary { /// BCrypt implementation. /// <remarks> /// /// BCrypt implements OpenBSD-style Blowfish password hashing using the scheme described in /// "A Future- /// Adaptable Password Scheme" by Niels Provos and David Mazieres. /// /// /// This password hashing system tries to thwart off-line password cracking using a /// computationally-intensive hashing algorithm, based on Bruce Schneier's Blowfish cipher. /// The work factor of the algorithm is parameterised, so it can be increased as computers /// get faster. /// /// /// Usage is really simple. To hash a password for the first time, call the <see /// cref="HashPassword(string)"/> method with a random salt, like this: /// /// string pw_hash = BCrypt.HashPassword(plain_password); /// /// To check whether a plaintext password matches one that has been hashed previously, /// use the <see cref="Verify"/> method: /// /// /// if (BCrypt.Verify(candidate_password, stored_hash)) /// Console.WriteLine("It match…

winform中TreeView透明背景
type: item
date: 2019-09-27T09:17:00+00:00
description: TreeView本身不支持透明背景，重写WndProc以支持背景图片。using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.ComponentModel; using System.Runtime.InteropServices; namespace MyControl { /// /// Displays a hierarchical collection of labeled items, each represented by a System.Windows.Forms.TreeNode. /// [ //Use the same attibutes as TreeView DesignerAttribute("System.Windows.Forms.Design.TreeViewDesigner, System.Design, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), DefaultPropertyAttribute("Nodes"), DefaultEventAttribute("AfterSelect") ] public class UTreeView : TreeView { Bitmap internalBitmap = null; Graphics internalGraphics = null; Image image = null; private void DisposeInternal() { if (internalGraphics != null) internalGraphics.Dispose(); if (internalBitmap != null) internalBitmap.Dispose(); } /// Releases resources. /// true = Both managed and unmanaged, false = Unmanaged only. protected override void Dispose(bool disposing) { if (disposing) DisposeInternal(); base.Dispose(disposing); } /// Occurs when window is resized. /// A System.EventArgs.Empty. /// <remarks>Recreates internal Graphics object. </remarks> protected override void OnResize(System.EventArgs e) { if (internalBitmap == null || internalBitmap.Width != Width || internalBitmap.Height != Height) { if (Width != 0 && Height != 0) { DisposeInternal(); internalBitmap = new Bitmap(Width, Height); internalGraphics = Graphics.FromImage(internalBitmap); } } } /// Occurs when a Windows message is dispatched. /// Message to process. /// <remarks>Overrides WM_PAINT, WM_ERASEBKGND.</remarks> public void setBackGround(Image bk = null) { if (bk != null) { image = bk; } else { Bitmap bm = new Bitmap(this.Parent.BackgroundImage, this.Parent.Width, this.Parent.Height); //绘制矩形，定义你需要截取的图像起始位置和宽高 Rectangle rs = new Rectangle(this.Location.X, this.Location.Y, this.Width, this.Height); //按矩形尺寸和起始位置截取bm的一部分 bm = bm.Clone(rs, System.Drawing.Imaging.PixelFormat.Un…

c#中如何跨线程调用windows窗体控件
type: item
date: 2019-09-19T06:08:00+00:00
description: 我们在做winform应用的时候，大部分情况下都会碰到使用多线程控制界面上控件信息的问题。然而我们并不能用传统方法来做这个问题，下面我将详细的介绍。首先来看传统方法：public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Thread thread = new Thread(ThreadFuntion); thread.IsBackground = true; thread.Start(); } private void ThreadFuntion() { while (true) { this.textBox1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } } }运行这段代码，我们会看到系统抛出一个异常：Cross-thread operation not valid:Control 'textBox1' accessed from a thread other than the thread it was created on .这是因为.net 2.0以后加强了安全机制，不允许在winform中直接跨线程访问控件的属性。那么怎么解决这个问题呢，下面提供几种方案。第一种方案，我们在Form1_Load()方法中加一句代码：private void Form1_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; Thread thread = new Thread(ThreadFuntion); thread.IsBackground = true; thread.Start(); }加入这句代码以后发现程序可以正常运行了。这句代码就是说在这个类中我们不检查跨线程的调用是否合法（如果没有加这句话运行也没有异常，那么说明系统以及默认的采用了不检查的方式）。然而，这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义，就会发现它是一个static的，也就是说无论我们在项目的什么地方修改了这个值，他就会在全局起作用。而且像这种跨线程访问是否存在异常，我们通常都会去检查。如果项目中其他人修改了这个属性，那么我们的方案就失败了，我们要采取另外的方案。下面来看第二种方案，就是使用delegate和invoke来从其他线程中控制控件信息。网上有很多人写了这种控制方式，然而我看了很多这种帖子，表明上看来是没有什么问题的，但是实际上并没有解决这个问题，首先来看网络上的那种不完善的方式：public partial class Form1 : Form { private delegate void FlushClient(); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Thread thread = new Thread(CrossThreadFlush); thread.IsBackground=true; thread.Start(); } private void CrossThreadFlush() { //将代理绑定到方法 FlushClient fc = new FlushClient(ThreadFuntion); this.BeginInvoke(fc);//调用代理 } private void ThreadFuntion() { while (true) { this.textBox1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } } }使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了，界面没有响应了。为什么会出现这个问题，我们只是让新开的线程无限循环刷新，理论上应该不会对主线程产生影响的。其实不然，这种方式其实相当于把这个新开的线程“注入”到了主控制线程中，它取得了主线程的控制。只要这个线程不返回，那么主线程将永远都无法响应。就算新开的线程中不使用无限循环，使可以返回了。这种方式的使用多线程也失去了它本来的意义。现在来让我们看看推荐的解决方案：using System; using System.Collections.Generic; using System.Comp…