C#winform程序只允许运行一个实例的几种方法详解
方法一
使用线程互斥变量. 通过定义互斥变量来判断是否已运行实例.
把program.cs文件里的Main()函数改为如下代码:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace QQ消息管理
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
//[STAThread]
//static void Main()
//{
// Application.EnableVisualStyles();
// Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new QQ消息管理());
//}
[DllImport("user32.dll")]
private static extern bool FlashWindow(IntPtr hWnd, bool bInvert);
[DllImport("user32.dll")]
private static extern bool FlashWindowEx(int pfwi);
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
private static void Main()
{
bool runone;
System.Threading.Mutex run = new System.Threading.Mutex(true, "single_test", out runone);
if (runone)
{
run.ReleaseMutex();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
QQ消息管理 frame = new QQ消息管理();
int hdc = frame.Handle.ToInt32(); // write to ...
Application.Run(frame);
IntPtr a = new IntPtr(hdc);
}
else
{
MessageBox.Show("该工具正在运行中,请勿重复启动!","提醒:",MessageBoxButtons.OK,MessageBoxIcon.Information);
return;
//IntPtr hdc = new IntPtr(1312810); // read from...
//bool flash = FlashWindow(hdc, true);
}
}
}
}
说明:程序中通过语句 System.Threading.Mutex run = new System.Threading.Mutex(true, “single_test”, out runone);来创建一个互斥体变量run,其中”single_test”为互斥体名,在此方法返回时,如果创建了局部互斥体或指定的命名系统互斥体,则布尔值runone为true;如果指定的命名系统互斥体已存在,则为 false。已命名的互斥体是系统范围的。
方法二
采用判断进程的方式,我们在运行程序前,查找进程中是否有同名的进程,同时运行位置也相同程,如是没有运行该程序,如果有就就不运行.在C#中应用System.Diagnostics名字空间中的Process类来实现,主要代码如下:
1,在program.cs文件中添加函数如下:
public static System.Diagnostics.Process RunningInstance()
{
System.Diagnostics.Process current = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
foreach (System.Diagnostics.Process process in processes) //查找相同名称的进程
{
if (process.Id != current.Id) //忽略当前进程
{ //确认相同进程的程序运行位置是否一样.
if (System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("/", @"/") == current.MainModule.FileName)
{ //Return the other process instance.
return process;
}
}
} //No other instance was found, return null.
return null;
}
2,把Main()函数改为如下代码:
static void Main()
{
if (RunningInstance() == null)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
MessageBox.Show("已经运行了一个实例了。");
}
}
方法三
全局原子法,创建程序前,先检查全局原子表中看是否存在特定原子A(创建时添加的),存在时停止创建,说明该程序已运行了一个实例;不存在则运行程序并想全局原子表中添加特定原子A;退出程序时要记得释放特定的原子A哦,不然要到关机才会释放。C#实现如下:
1.申明WinAPI函数接口
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern UInt32 GlobalAddAtom(String lpString); //添加原子
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern UInt32 GlobalFindAtom(String lpString); //查找原子
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern UInt32 GlobalDeleteAtom(UInt32 nAtom); //删除原子
2.修改Main()函数如下:
static void Main()
{
if (GlobalFindAtom("jiaao_test") == 77856768) //没找到原子"jiaao_test"
{
GlobalAddAtom("jiaao_test"); //添加原子"jiaao_test"
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
MessageBox.Show("已经运行了一个实例了。");
}
}
3.在FormClosed事件中添加如下代码:
GlobalDeleteAtom(GlobalFindAtom("jiaao_test"));//删除原子"jiaao_test"
方法四
通过进程判断是否启动:
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//获取当前进程的ID
int pId = Process.GetCurrentProcess().Id;
bool isRun = false;
foreach (Process p in Process.GetProcessesByName("CallMaster"))
{
//取得当前程序的进程,进行比较
if (Common.GetPath().ToLower() == p.MainModule.FileName.ToLower())
{
if (pId != p.Id)
{
isRun = true;
break;
}
}
}
if (isRun==true)
{
Application.Exit();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
}
利用反射获取当前应用程序的全路径:
public static string GetPath()
{
return System.Reflection.Assembly.GetExecutingAssembly().Location;
}
方法五
通过线程互斥判断是否启动
static class Program
{
private static System.Threading.Mutex mutex;
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
mutex = new System.Threading.Mutex(true, "OnlyRun");
if (mutex.WaitOne(0, false))
{
Application.Run(new MainForm());
}
else
{
MessageBox.Show("程序已经在运行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
Application.Exit();
}
}
}
另附
c#中怎样判断一个程序是否正在运行?
if (System.Diagnostics.Process.GetProcessesByName("程序进程中的名称").ToList().Count > 0)
{
//存在
}
else
{
//不存在
}
改变DataGridView的行列方格颜色
DataGridView1.Rows[k].DefaultCellStyle.BackColor = Color.Yellow
DataGridView1.Rows[k].DefaultCellStyle.ForeColor = Color.Yellow
无法编辑
是因为把用户操作的几个选项关掉了,打开删除就可以修改了
字典排序
Dictionary<int, string> dic1Asc = test.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
Console.WriteLine("小到大排序");
foreach(KeyValuePair<int,string> k in dic1Asc){
Console.WriteLine("key:" +k.Key +" value:" + k.Value);
}
Console.WriteLine("大到小排序");
Dictionary<int, string> dic1desc = test.OrderByDescending(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
foreach (KeyValuePair<int, string> k in dic1desc)
{
Console.WriteLine("key:" + k.Key + " value:" + k.Value);
}
在datagridview中添加button按钮
Button btn = new Button();
dataGridView1.Rows[dataIndex].Cells[3].Value = btn;
//------------------------------------------------------------------------------------------------
/// <summary>
/// 鼠标移进格子的时候
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dataGridView1_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender; //如果是"Link"列,被點選
if (dgv.Columns[e.ColumnIndex].Name == "Column7" && e.RowIndex < dgv.Rows.Count && e.RowIndex > -1)
{
string titlePath = dataGridView1.Rows[e.RowIndex].Cells[3].Tag.ToString();
ImageForm1 imgForm = ImageForm1.GetSingleton(titlePath); // 无参数
imgForm.Show();
imgForm.Activate();
var formX = this.Location.X + this.Width * 3 / 5;
var formY = this.Location.Y + this.Height / 3;
imgForm.Location = new Point(formX, formY);
dataGridView1.Rows[e.RowIndex].Cells[2].Tag = imgForm;
}
}
/// <summary>
/// 鼠标移出格子的时候
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender; //如果是"Link"列,被點選
if (dgv.Columns[e.ColumnIndex].Name == "Column7" && e.RowIndex < dgv.Rows.Count && e.RowIndex > -1)
{
ImageForm1 imgForm = dataGridView1.Rows[e.RowIndex].Cells[2].Tag as ImageForm1;
imgForm.Hide();
}
}
RichTextBox
滚动光爆到最后一行
richTextBox.ScrollToCaret();
隐藏任务栏图标
this.ShowInTaskbar = false;
Winform窗口起始位置
int x = (System.Windows.Forms.SystemInformation.WorkingArea.Width - this.Size.Width) / 2;
int y = (System.Windows.Forms.SystemInformation.WorkingArea.Height - this.Size.Height) / 2;
this.StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定
this.Location = (Point)new Size(x, y); //窗体的起始位置为(x,y)
System.Windows.Forms.SystemInformation.WorkingArea.Width //屏幕宽度
System.Windows.Forms.SystemInformation.WorkingArea.Height //屏幕高度(去系统任务栏,当显示有任务栏的时候)
this.Size.Width //自己窗体的宽度,
this.Size.Width //自己窗体的高度
this.ClientRectangle.Width //工作区域宽度
this.ClientRectangle.Height //工作区域高度设置窗口初始位置
this.StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定
this.StartPosition = FormStartPosition.CenterParent; //窗体在其父窗体中居中
this.StartPosition = FormStartPosition.CenterScreen; //窗体在当前显示窗口中居中,尺寸在窗体大小中指定
this.StartPosition = FormStartPosition.WindowsDefaultBounds; //窗体定位在windows默认位置,边界也由windows默认决定
this.StartPosition = FormStartPosition.WindowsDefaultLocation; //窗体定位在windows默认位置,尺寸在窗体大小中指定
通过指定窗体Locaiton来,设定窗体位置
this.StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定
this.Location = (Point)new Size(0, 0); //窗体的起始位置为0,0
创建窗体时, 设置宽度和高度
this.ClientSize = new System.Drawing.Size(x1,y1); //X1 为宽度,Y1为高度
获取屏幕大小(using System.Drawing)
Rectangle rect = Screen.GetWorkingArea(this);
Point p = new Point(rect.Width,rect.Height);
this.Location = p;
关闭所有子窗口
//关闭所有子窗口,可以执行子窗口的closing方法
FormCollection childCollection = Application.OpenForms;
for (int i = childCollection.Count; i-- > 0;)
{
if (childCollection[i].Name != this.Name) childCollection[i].Close();
}
mysql相关包
dapper 2.0.30
mysql 8.0.20.0
追加文字到txt并换行
if (richTextBox1.Text.Length == 0)
{
return;
}
string logPath = 原卷答案对应核查.日志缓存 + "原卷加编上传日志/";
if (!Directory.Exists(logPath))
{
Directory.CreateDirectory(logPath);
}
string fileName = logPath + DateTime.Now.Year + "年-" + DateTime.Now.Month + "月-" + DateTime.Now.Day + "日" + "-原卷加编上传日志" + ".txt";
if (!File.Exists(fileName))
{
FileInfo logFile = new FileInfo(fileName);
FileStream fs = logFile.Create();
fs.Close();
}
StreamWriter sw = File.AppendText(fileName);
sw.WriteLine(richTextBox1.Text);
sw.Flush();
sw.Close();
删除文件夹下的所有文件
DirectoryInfo dir = new DirectoryInfo(open.SelectedPath);
dir.Delete(true);
递归遍历所有文件
/// <summary>
/// 递归寻找文件
/// </summary>
/// <param name="dir"></param>
/// <param name="list"></param>
private void Director(string dir, List<string> list)
{
DirectoryInfo d = new DirectoryInfo(dir);
FileInfo[] files = d.GetFiles();//文件
DirectoryInfo[] directs = d.GetDirectories();//文件夹
foreach (FileInfo f in files)
{
list.Add(f.FullName);//添加文件路径到列表中
}
//获取子文件夹内的文件列表,递归遍历
foreach (DirectoryInfo dd in directs)
{
Director(dd.FullName, list);
}
}
Bitmap转Bytes数组
//首先是Bitmap 转 MemoryStream
MemoryStream ms = new MemoryStream();
bitmap.save(ms, ImageFormat.Jpeg);
ms.Seek(0, SeekOrigin.Begin); //一定不要忘记将流的初始位置重置
//然后是MemoryStream 转 Byte数组
byte bytes = new byte[ms.Length];
ms.Read(bytes, 0, bytes.Length); //如果上面流没有seek 则这里读取的数据全会为0
ms.Dispose();
转换小数计算
float f = (int)i 1.0000f / (int)j 1.0000f;
判断图片是否为全白或者部分白色
//将PDF页转换成bitmap图形
Image img = doc.SaveAsImage(i);
Bitmap bitmap = new Bitmap(img);
//图片总像素
int intCount = 0;
//按像素遍历
for (int intY = 0; intY < img.Height; intY++)
{
for (int intX = 0; intX < img.Width; intX++)
{
if (bitmap.GetPixel(intX, intY).GetBrightness().Equals(1))
{
intCount += 1;
}
}
}
bitmap.Dispose();
if (intCount < 4000)
{
img.Dispose();
continue;
}
C#获取当前程序运行路径的方法集合
//获取当前进程的完整路径,包含文件名(进程名)。
string str = this.GetType().Assembly.Location;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取新的 Process 组件并将其与当前活动的进程关联的主模块的完整路径,包含文件名(进程名)。
string str = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取和设置当前目录(即该进程从中启动的目录)的完全限定路径。
string str = System.Environment.CurrentDirectory;
result: X:\xxx\xxx (.exe文件所在的目录)
//获取当前 Thread 的当前应用程序域的基目录,它由程序集冲突解决程序用来探测程序集。
string str = System.AppDomain.CurrentDomain.BaseDirectory;
result: X:\xxx\xxx\ (.exe文件所在的目录+”\”)
//获取和设置包含该应用程序的目录的名称。(推荐)
string str = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
result: X:\xxx\xxx\ (.exe文件所在的目录+”\”)
//获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。
string str = System.Windows.Forms.Application.StartupPath;
result: X:\xxx\xxx (.exe文件所在的目录)
//获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。
string str = System.Windows.Forms.Application.ExecutablePath;
result: X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
//获取应用程序的当前工作目录(不可靠)。
string str = System.IO.Directory.GetCurrentDirectory();
result: X:\xxx\xxx (.exe文件所在的目录)
DateTime用法
C#里内置的DateTime基本上都可以实现这些功能,巧用DateTime会使你处理这些事来变轻松多了
今天
DateTime.Now.Date.ToShortDateString();
昨天,就是今天的日期减一
DateTime.Now.AddDays(-1).ToShortDateString();
明天,同理,加一
DateTime.Now.AddDays(1).ToShortDateString();
本周(要知道本周的第一天就得先知道今天是星期几,从而得知本周的第一天就是几天前的那一天,要注意的是这里的每一周是从周日始至周六止
DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
如果你还不明白,再看一下中文显示星期几的方法就应该懂了
由于DayOfWeek返回的是数字的星期几,我们要把它转换成汉字方便我们阅读,有些人可能会用switch来一个一个地对照,其实不用那么麻烦的
string[] Day = new string[] { “星期日”, “星期一”, “星期二”, “星期三”, “星期四”, “星期五”, “星期六” };
Day[Convert.ToInt16(DateTime.Now.DayOfWeek)];
上周,同理,一个周是7天,上周就是本周再减去7天,下周也是一样
DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
下周
DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
本月,很多人都会说本月的第一天嘛肯定是1号,最后一天就是下个月一号再减一天。当然这是对的
一般的写法
DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + “1”; //第一天
DateTime.Parse(DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + “1”).AddMonths(1).AddDays(-1).ToShortDateString();//最后一天
巧用C#里ToString的字符格式化更简便
DateTime.Now.ToString(“yyyy-MM-01”);
DateTime.Parse(DateTime.Now.ToString(“yyyy-MM-01”)).AddMonths(1).AddDays(-1).ToShortDateString();
上个月,减去一个月份
DateTime.Parse(DateTime.Now.ToString(“yyyy-MM-01”)).AddMonths(-1).ToShortDateString();
DateTime.Parse(DateTime.Now.ToString(“yyyy-MM-01”)).AddDays(-1).ToShortDateString();
下个月,加去一个月份
DateTime.Parse(DateTime.Now.ToString(“yyyy-MM-01”)).AddMonths(1).ToShortDateString();
DateTime.Parse(DateTime.Now.ToString(“yyyy-MM-01”)).AddMonths(2).AddDays(-1).ToShortDateString();
7天后
DateTime.Now.Date.ToShortDateString();
DateTime.Now.AddDays(7).ToShortDateString();
7天前
DateTime.Now.AddDays(-7).ToShortDateString();
DateTime.Now.Date.ToShortDateString();
本年度,用ToString的字符格式化我们也很容易地算出本年度的第一天和最后一天
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).ToShortDateString();
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).AddYears(1).AddDays(-1).ToShortDateString();
上年度,不用再解释了吧
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).AddYears(-1).ToShortDateString();
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).AddDays(-1).ToShortDateString();
下年度
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).AddYears(1).ToShortDateString();
DateTime.Parse(DateTime.Now.ToString(“yyyy-01-01”)).AddYears(2).AddDays(-1).ToShortDateString();
本季度,很多人都会觉得这里难点,需要写个长长的过程来判断。其实不用的,我们都知道一年四个季度,一个季度三个月
首先我们先把日期推到本季度第一个月,然后这个月的第一天就是本季度的第一天了
DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”);
同理,本季度的最后一天就是下季度的第一天减一
DateTime.Parse(DateTime.Now.AddMonths(3 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”)).AddDays(-1).ToShortDateString();
下季度,相信你们都知道了。。。。收工
DateTime.Now.AddMonths(3 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”);
DateTime.Parse(DateTime.Now.AddMonths(6 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”)).AddDays(-1).ToShortDateString();
上季度
DateTime.Now.AddMonths(-3 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”);
DateTime.Parse(DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 3)).ToString(“yyyy-MM-01”)).AddDays(-1).ToShortDateString();
======简单补充======
c#中如何获取时间!
1、DateTime 数字型
System.DateTime currentTime=new System.DateTime();
1.1 取当前年月日时分秒
currentTime=System.DateTime.Now;
1.2 取当前年
int 年=currentTime.Year;
1.3 取当前月
int 月=currentTime.Month;
1.4 取当前日
int 日=currentTime.Day;
1.5 取当前时
int 时=currentTime.Hour;
1.6 取当前分
int 分=currentTime.Minute;
1.7 取当前秒
int 秒=currentTime.Second;
1.8 取当前毫秒
int 毫秒=currentTime.Millisecond;
(变量可用中文)
1.9 取中文日期显示——年月日时分
string strY=currentTime.ToString(“f”); //不显示秒
1.10 取中文日期显示年月
string strYM=currentTime.ToString(“y”);
1.11 取中文日期显示月日
string strMD=currentTime.ToString(“m”);
1.12 取中文年月日
string strYMD=currentTime.ToString(“D”);
1.13 取当前时分,格式为:14:24
string strT=currentTime.ToString(“t”);
1.14 取当前时间,格式为:2003-09-23T14:46:48
string strT=currentTime.ToString(“s”);
1.15 取当前时间,格式为:2003-09-23 14:48:30Z
string strT=currentTime.ToString(“u”);
1.16 取当前时间,格式为:2003-09-23 14:48
string strT=currentTime.ToString(“g”);
1.17 取当前时间,格式为:Tue, 23 Sep 2003 14:52:40 GMT
string strT=currentTime.ToString(“r”);
1.18获得当前时间 n 天后的日期时间
DateTime newDay = DateTime.Now.AddDays(100);
string strT = DateTime.Now.ToString(“yyyy-MM-dd HH:mm:ss”);
System.DateTime currentTime=new System.DateTime();
currentTime=System.DateTime.Now; //取当前年月日时分秒
string Y=currentTime.Year.ToString(); //取当前年
string M=currentTime.Month.ToString(); //取当前月
string D=currentTime.Day.ToString(); //取当前日
string T=currentTime.Hour.ToString(); //取当前时
string MM=currentTime.Minute.ToString(); //取当前分
string S=currentTime.Second.ToString(); //取当前秒
string SS=currentTime.Millisecond.ToString(); //取当前毫秒
string FileName=Y+M+D+T+MM+S+SS+”.Html”; //联接后,得到长文件名