SVN r1118

SVN-Revision: r1118
This commit is contained in:
tdx
2026-02-09 01:56:27 +00:00
parent 48a57b70a4
commit bfdbb83708
8 changed files with 1047 additions and 31 deletions
@@ -74,27 +74,4 @@ namespace Lskj.GetSecretKey
{
SqlHelper.ExecuteNonQuery(sqlNameStr);
this.oldUserName = this.userName;
}
string sqlPsdStr = "ALTER LOGIN {0} WITH PASSWORD = '{1}'";
sqlPsdStr = string.Format(sqlPsdStr, userName, passWord);
string nConnection = "Server={0};Database={1};Persist Security Info=True;User ID=" + userName + ";Password=" + oldPassWord + ";Connection Timeout=5;MultipleActiveResultSets=true";
nConnection = AESUtil.Encrypt(nConnection);
SqlHelper._connection = null;
if (DBConfig.Instance.CreateConnection(nConnection))
{
SqlHelper.ExecuteNonQuery(sqlPsdStr);
this.oldPassWord = passWord;
}
}
catch (Exception ex)
{
MessageUtil.Show(ex.Message);
return;
}
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}
}
+98
View File
@@ -0,0 +1,98 @@
namespace Lskj.GetSecretKey
{
partial class LoginFrm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.userNameEdit = new DevExpress.XtraEditors.TextEdit();
this.labelControl2 = new DevExpress.XtraEditors.LabelControl();
this.passWordEidt = new DevExpress.XtraEditors.TextEdit();
this.labelControl1 = new DevExpress.XtraEditors.LabelControl();
this.setPanel = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.userNameEdit.Properties)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.passWordEidt.Properties)).BeginInit();
this.SuspendLayout();
//
// userNameEdit
//
this.userNameEdit.AllowDrop = true;
this.userNameEdit.Location = new System.Drawing.Point(85, 24);
this.userNameEdit.Margin = new System.Windows.Forms.Padding(2);
this.userNameEdit.Name = "userNameEdit";
this.userNameEdit.Properties.Appearance.Font = new System.Drawing.Font("宋体", 12F);
this.userNameEdit.Properties.Appearance.Options.UseFont = true;
this.userNameEdit.Size = new System.Drawing.Size(155, 22);
this.userNameEdit.TabIndex = 7;
//
// labelControl2
//
this.labelControl2.Appearance.Font = new System.Drawing.Font("宋体", 12F);
this.labelControl2.Location = new System.Drawing.Point(39, 27);
this.labelControl2.Margin = new System.Windows.Forms.Padding(2);
this.labelControl2.Name = "labelControl2";
this.labelControl2.Size = new System.Drawing.Size(48, 16);
this.labelControl2.TabIndex = 6;
this.labelControl2.Text = "账号:";
//
// passWordEidt
//
this.passWordEidt.Location = new System.Drawing.Point(86, 64);
this.passWordEidt.Margin = new System.Windows.Forms.Padding(2);
this.passWordEidt.Name = "passWordEidt";
this.passWordEidt.Properties.Appearance.Font = new System.Drawing.Font("宋体", 12F);
this.passWordEidt.Properties.Appearance.Options.UseFont = true;
this.passWordEidt.Size = new System.Drawing.Size(155, 22);
this.passWordEidt.TabIndex = 5;
//
// labelControl1
//
this.labelControl1.Appearance.Font = new System.Drawing.Font("宋体", 12F);
this.labelControl1.Location = new System.Drawing.Point(39, 66);
this.labelControl1.Margin = new System.Windows.Forms.Padding(2);
this.labelControl1.Name = "labelControl1";
this.labelControl1.Size = new System.Drawing.Size(48, 16);
this.labelControl1.TabIndex = 4;
this.labelControl1.Text = "密码:";
//
// setPanel
//
this.setPanel.BackgroundImage = global::Lskj.GetSecretKey.Properties.Resources.;
this.setPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.setPanel.Location = new System.Drawing.Point(261, 47);
this.setPanel.Name = "setPanel";
this.setPanel.Size = new System.Drawing.Size(32, 32);
this.setPanel.TabIndex = 25;
//
// LoginFrm
//
this.Appearance.BackColor = System.Drawing.SystemColors.Control;
this.Appearance.Options.UseBackColor = true;
this.Appearance.Options.UseFont = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+432
View File
@@ -0,0 +1,432 @@
using Lskj.Control;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Windows.Forms;
namespace Lskj.GetSecretKey
{
public partial class LoginFrm : BaseForm
{
private ContextMenuStrip _ctx;
public LoginFrm()
{
InitializeComponent();
SecureUserStore.EnsureInitialized(); // 初始化本地存储(含默认账号)
InitUi();
WireEvents();
}
#region UI &
private void InitUi()
{
// 密码框设置为 * 掩码(兼容 TextBox / DevExpress TextEdit
SetPasswordMask(passWordEidt);
// 回填上次成功登录账号
var last = SecureUserStore.GetLastUser();
if (!string.IsNullOrEmpty(last)) { userNameEdit.Text = last; passWordEidt.Focus(); }
else userNameEdit.Focus();
// 提示
try
{
setPanel.Cursor = Cursors.Hand;
var tip = new ToolTip();
tip.SetToolTip(setPanel, "左键:修改密码(需当前密码验证)\r\n右键:更多操作(重置密码…)");
}
catch { /* ignore */ }
// 右键菜单
_ctx = new ContextMenuStrip();
var miChange = new ToolStripMenuItem("修改密码…", null, (s, e) => DoChangePassword());
var miReset = new ToolStripMenuItem("重置密码…", null, (s, e) => DoResetPassword());
_ctx.Items.AddRange(new ToolStripItem[] { miChange, new ToolStripSeparator(), miReset });
setPanel.ContextMenuStrip = _ctx;
}
private void WireEvents()
{
// 回车登录
passWordEidt.KeyDown += (s, e) => { if (e.KeyCode == Keys.Enter) TryLogin(); };
// 左键点击 setPanel -> 修改密码(需当前密码验证通过)
setPanel.Click += (s, e) => {
if (e is MouseEventArgs me && me.Button == MouseButtons.Right) return;
DoChangePassword();
};
// 右键已经由 ContextMenuStrip 处理
}
#endregion
#region //
private void TryLogin()
{
string user = (userNameEdit.Text ?? "").Trim();
string pwd = passWordEidt.Text ?? "";
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pwd))
{
MessageBox.Show("请输入账号和密码。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (SecureUserStore.Validate(user, pwd))
{
SecureUserStore.SetLastUser(user); // 记住本次成功登录账号
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
MessageBox.Show("账号或密码错误。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
passWordEidt.SelectAll();
passWordEidt.Focus();
}
}
private void DoChangePassword()
{
string user = (userNameEdit.Text ?? "").Trim();
string currPwd = passWordEidt.Text ?? "";
if (string.IsNullOrEmpty(user))
{
MessageBox.Show("请先在账号框输入要修改密码的账号(例如:管理员、管理员1)。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
userNameEdit.Focus();
return;
}
if (!SecureUserStore.Exists(user))
{
MessageBox.Show("账号不存在,仅支持:管理员、管理员1。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
userNameEdit.Focus(); userNameEdit.SelectAll();
return;
}
// 必须先通过“账号+当前密码”验证
if (!SecureUserStore.Validate(user, currPwd))
{
MessageBox.Show("请先在密码框输入该账号的当前密码并验证通过,然后再修改。", "需要验证", MessageBoxButtons.OK, MessageBoxIcon.Warning);
passWordEidt.Focus(); passWordEidt.SelectAll();
return;
}
using (var dlg = new ChangePasswordDialog(user))
{
if (dlg.ShowDialog(this) == DialogResult.OK)
{
SecureUserStore.SetPassword(user, dlg.NewPassword);
MessageBox.Show("密码已更新并安全保存到本地。", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
private void DoResetPassword()
{
// 仅管理员权限允许重置
if (!SecurityUtil.IsAdministrator())
{
MessageBox.Show("需要以【管理员身份运行】程序后才能重置密码。", "权限不足", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
using (var dlg = new ResetConfirmDialog())
{
if (dlg.ShowDialog(this) != DialogResult.OK) return;
// 校验重置口令(你可以修改 SecureReset.ResetSecret 自定义口令)
if (!SecureReset.VerifyResetCode(dlg.ResetCode))
{
MessageBox.Show("重置口令不正确。", "校验失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
string user = (userNameEdit.Text ?? "").Trim();
if (string.IsNullOrEmpty(user))
{
// 未指定账号 -> 询问是否重置所有内置账号
if (MessageBox.Show("未填写账号,是否重置所有内置账号为默认密码 123456?",
"重置确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
foreach (var u in SecureUserStore.BuiltinUsers) SecureUserStore.ResetToDefault(u);
MessageBox.Show("所有内置账号已重置为 123456。", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
else
{
if (!SecureUserStore.Exists(user))
{
MessageBox.Show("账号不存在,无法重置。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (MessageBox.Show($"确定将「{user}」密码重置为 123456",
"重置确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
SecureUserStore.ResetToDefault(user);
MessageBox.Show("已重置为 123456。", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
#endregion
#region * TextBox / DevExpress TextEdit
private static void SetPasswordMask(System.Windows.Forms.Control ctrl)
{
try
{
var t = ctrl.GetType();
var propPwdChar = t.GetProperty("PasswordChar");
if (propPwdChar != null && propPwdChar.CanWrite) propPwdChar.SetValue(ctrl, '*', null);
var propUseSys = t.GetProperty("UseSystemPasswordChar");
if (propUseSys != null && propUseSys.CanWrite) propUseSys.SetValue(ctrl, true, null);
var propProperties = t.GetProperty("Properties");
if (propProperties != null)
{
var propsObj = propProperties.GetValue(ctrl, null);
if (propsObj != null)
{
var px = propsObj.GetType();
var p1 = px.GetProperty("PasswordChar"); if (p1 != null && p1.CanWrite) p1.SetValue(propsObj, '*', null);
var p2 = px.GetProperty("UseSystemPasswordChar"); if (p2 != null && p2.CanWrite) p2.SetValue(propsObj, true, null);
}
}
}
catch { /* ignore */ }
}
#endregion
}
#region &
internal static class SecurityUtil
{
public static bool IsAdministrator()
{
try
{
using (var identity = WindowsIdentity.GetCurrent())
{
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
catch { return false; }
}
public static string Sha256(string s)
{
using (var sha = SHA256.Create())
{
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(s ?? ""));
var sb = new StringBuilder(bytes.Length * 2);
foreach (var b in bytes) sb.Append(b.ToString("x2"));
return sb.ToString();
}
}
}
internal static class SecureReset
{
// ★ 重置口令(明文)。建议你改成自己的:仅内部人员知悉。
private const string ResetSecret = "Lskj#Reset2025";
private static readonly string ResetHash = SecurityUtil.Sha256(ResetSecret);
public static bool VerifyResetCode(string input)
=> string.Equals(SecurityUtil.Sha256(input ?? ""), ResetHash, StringComparison.OrdinalIgnoreCase);
}
#endregion
#region DPAPI +
internal static class SecureUserStore
{
// %LOCALAPPDATA%\Lskj.GetSecretKey\
private static readonly string AppDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Lskj.GetSecretKey");
private static readonly string StorePath = Path.Combine(AppDir, "users.sec"); // 用户: 密文
private static readonly string LastUserPath = Path.Combine(AppDir, "lastuser.dat"); // 纯文本:上一次成功登录账号
private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("Lskj.GetSecretKey|DPAPI|v1");
internal static readonly string[] BuiltinUsers = new[] { "管理员", "管理员1" }; // 供外部枚举使用
private const string DefaultPassword = "123456";
// 缓存:用户名 -> Base64(Protect(UTF8(pwd)))
private static readonly Dictionary<string, string> _cipherMap = new Dictionary<string, string>(StringComparer.Ordinal);
private static bool _initialized;
private static readonly object _lock = new object();
public static void EnsureInitialized()
{
if (_initialized) return;
lock (_lock)
{
if (_initialized) return;
Directory.CreateDirectory(AppDir);
if (!File.Exists(StorePath))
{
foreach (var u in BuiltinUsers) _cipherMap[u] = ProtectToBase64(DefaultPassword);
Persist();
}
else
{
Load();
bool changed = false;
foreach (var u in BuiltinUsers)
if (!_cipherMap.ContainsKey(u)) { _cipherMap[u] = ProtectToBase64(DefaultPassword); changed = true; }
if (changed) Persist();
}
_initialized = true;
}
}
public static bool Exists(string user) { EnsureInitialized(); return _cipherMap.ContainsKey(user); }
public static bool Validate(string user, string plainPwd)
{
EnsureInitialized();
if (!_cipherMap.TryGetValue(user, out var b64)) return false;
try { return UnprotectFromBase64(b64) == (plainPwd ?? ""); }
catch { return false; }
}
public static void SetPassword(string user, string newPwd)
{
EnsureInitialized();
if (string.IsNullOrEmpty(user)) return;
_cipherMap[user] = ProtectToBase64(newPwd ?? "");
Persist();
}
public static void ResetToDefault(string user)
{
EnsureInitialized();
if (string.IsNullOrEmpty(user)) return;
_cipherMap[user] = ProtectToBase64(DefaultPassword);
Persist();
}
public static void SetLastUser(string user)
{
try { File.WriteAllText(LastUserPath, user ?? "", Encoding.UTF8); }
catch { /* ignore */ }
}
public static string GetLastUser()
{
try { return File.Exists(LastUserPath) ? (File.ReadAllText(LastUserPath, Encoding.UTF8).Trim()) : ""; }
catch { return ""; }
}
private static void Load()
{
_cipherMap.Clear();
foreach (var line in File.ReadAllLines(StorePath, Encoding.UTF8))
{
if (string.IsNullOrWhiteSpace(line)) continue;
var idx = line.IndexOf('=');
if (idx <= 0) continue;
var key = line.Substring(0, idx);
var val = line.Substring(idx + 1);
if (!_cipherMap.ContainsKey(key)) _cipherMap[key] = val;
}
}
private static void Persist()
{
var sb = new StringBuilder();
foreach (var kv in _cipherMap) sb.Append(kv.Key).Append('=').Append(kv.Value).Append('\n');
File.WriteAllText(StorePath, sb.ToString(), Encoding.UTF8);
}
private static string ProtectToBase64(string plain)
{
var bytes = Encoding.UTF8.GetBytes(plain ?? "");
var cipher = ProtectedData.Protect(bytes, Entropy, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(cipher);
}
private static string UnprotectFromBase64(string base64)
{
var cipher = Convert.FromBase64String(base64 ?? "");
var plain = ProtectedData.Unprotect(cipher, Entropy, DataProtectionScope.CurrentUser);
return Encoding.UTF8.GetString(plain);
}
}
#endregion
#region
internal sealed class ChangePasswordDialog : Form
{
private readonly string _user;
private TextBox txtNew, txtConfirm;
private Button btnOk, btnCancel;
public string NewPassword { get; private set; }
public ChangePasswordDialog(string user)
{
_user = user;
BuildUi();
}
private void BuildUi()
{
this.Text = $"修改密码 - {_user}";
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.StartPosition = FormStartPosition.CenterParent;
this.ClientSize = new Size(340, 170);
this.MaximizeBox = false; this.MinimizeBox = false;
var lbl1 = new Label { Text = "新密码:", AutoSize = true, Location = new Point(20, 28) };
var lbl2 = new Label { Text = "确认新密码:", AutoSize = true, Location = new Point(20, 68) };
txtNew = new TextBox { Location = new Point(130, 24), Width = 180, UseSystemPasswordChar = true, PasswordChar = '*' };
txtConfirm = new TextBox { Location = new Point(130, 64), Width = 180, UseSystemPasswordChar = true, PasswordChar = '*' };
btnOk = new Button { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(130, 110), Width = 80 };
btnCancel = new Button { Text = "取消", DialogResult = DialogResult.Cancel, Location = new Point(230, 110), Width = 80 };
btnOk.Click += (s, e) =>
{
if (string.IsNullOrEmpty(txtNew.Text))
{
MessageBox.Show("新密码不能为空。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.DialogResult = DialogResult.None; return;
}
if (txtNew.Text != txtConfirm.Text)
{
MessageBox.Show("两次输入的密码不一致。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.DialogResult = DialogResult.None; return;
}
NewPassword = txtNew.Text;
};
this.Controls.AddRange(new System.Windows.Forms.Control[] { lbl1, txtNew, lbl2, txtConfirm, btnOk, btnCancel });
this.AcceptButton = btnOk; this.CancelButton = btnCancel;
}
}
#endregion
#region
internal sealed class ResetConfirmDialog : Form
{
private TextBox txtCode;
private Button btnOk, btnCancel;
public string ResetCode { get; private set; }
public ResetConfirmDialog() { BuildUi(); }
private void BuildUi()
{
this.Text = "输入重置口令";
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.StartPosition = FormStartPosition.CenterParent;
this.ClientSize = new Size(360, 150);
this.MaximizeBox = false; this.MinimizeBox = false;
var lbl = new Label { Text = "重置口令:", AutoSize = true, Location = new Point(20, 30)
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -35,22 +35,27 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="DevExpress.Data.v15.2" />
<Reference Include="DevExpress.Utils.v15.2" />
<Reference Include="DevExpress.XtraEditors.v15.2" />
<Reference Include="Lskj.Control">
<HintPath>..\..\Debug\Lskj.Control.dll</HintPath>
<Reference Include="Lskj.Business">
<HintPath>..\..\..\..\下载\xwechat_files\wxid_9htys9sllfcy22_4c66\msg\file\2025-09\Lskj.Business.dll</HintPath>
</Reference>
<Reference Include="Lskj.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Debug\Lskj.Core.dll</HintPath>
<Reference Include="Lskj.Control">
<HintPath>..\..\..\..\下载\xwechat_files\wxid_9htys9sllfcy22_4c66\msg\file\2025-09\Lskj.Control.dll</HintPath>
</Reference>
<Reference Include="Lskj.Core">
<HintPath>..\..\..\..\下载\xwechat_files\wxid_9htys9sllfcy22_4c66\msg\file\2025-09\Lskj.Core.dll</HintPath>
</Reference>
<Reference Include="Lskj.Data">
<HintPath>..\..\Debug\Lskj.Data.dll</HintPath>
<HintPath>..\..\..\..\下载\xwechat_files\wxid_9htys9sllfcy22_4c66\msg\file\2025-09\Lskj.Data.dll</HintPath>
</Reference>
<Reference Include="Lskj.Util">
<HintPath>..\..\Debug\Lskj.Util.dll</HintPath>
<HintPath>..\..\..\..\下载\xwechat_files\wxid_9htys9sllfcy22_4c66\msg\file\2025-09\Lskj.Util.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
@@ -70,6 +75,7 @@
<Reference Include="System.Runtime, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.Threading.Tasks, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
@@ -95,14 +101,24 @@
<Compile Include="FrmPsdChange.Designer.cs">
<DependentUpon>FrmPsdChange.cs</DependentUpon>
</Compile>
<Compile Include="LoginFrm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="LoginFrm.Designer.cs">
<DependentUpon>LoginFrm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="winApi.cs" />
<EmbeddedResource Include="FrmMain.resx">
<DependentUpon>FrmMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FrmPsdChange.resx">
<DependentUpon>FrmPsdChange.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="LoginFrm.resx">
<DependentUpon>LoginFrm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\licenses.licx" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
@@ -129,6 +145,9 @@
<ItemGroup>
<None Include="修改密码.png" />
</ItemGroup>
<ItemGroup>
<Content Include="logo.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

+370
View File
@@ -0,0 +1,370 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace Lskj.Main.Model
{
public static class WinAPI
{
#region
public const int GWL_WNDPROC = -4; //得到窗口回调函数的地址,或者句柄。得到后必须使用CallWindowProc函数来调用
public const int GWL_HINSTANCE = -6; //得到应用程序运行实例的句柄
public const int GWL_HWNDPARENT = -8; //得到父窗口的句柄
public const int GWL_STYLE = -16; //得到窗口风格
public const int GWL_EXSTYLE = -20; //得到扩展的窗口风格
public const int GWL_USERDATA = -21; //得到和窗口相关联的32位的值(每一个窗口都有一个有意留给创建窗口的应用程序是用的32位的值)
public const int GWL_ID = -12; //得到窗口的标识符
public const int DWL_MSGRESULT = 0;
public const int DWL_DLGPROC = 4;
public const int DWL_USER = 8;
public const int HWND_BOTTOM = 1;
public const int HWND_TOP = 0;
public const int HWND_TOPMOST = -1;
public const int HWND_NOTOPMOST = -2;
public const int SWP_DRAW = 0x20;
public const int SWP_HIDEWINDOW = 0x80;
public const int SWP_NOACTIVATE = 0x10;
public const int SWP_NOMOVE = 0x2;
public const int SWP_NOREDRAW = 0x8;
public const int SWP_NOSIZE = 0x1;
public const int SWP_NOZORDER = 0x4;
public const int SWP_SHOWWINDOW = 0x40;
public const int WS_OVERLAPPED = 0;
public const int WS_BORDER = 0x800000;
public const int WS_CAPTION = 0xC00000;
public const int WS_CHILD = 0x40000000;
public const int WS_DLGFRAME = 0x400000;
public const int WS_SIZEBOX = 0x40000;
public const int WS_MAXIMIZEBOX = 0x10000;
public const int WS_MINIMIZEBOX = 0x20000;
public const int WS_SYSMENU = 0x80000;
public const int WS_HSCROLL = 0x100000;
public const int WS_VSCROLL = 0x200000;
public const int WA_INACTIVE = 0;
public const int WA_ACTIVE = 1;
public const int WA_CLICKACTIVE = 2;
public const int WM_NOTIFY = 0x004E;
public const int WM_ACTIVATE = 0x0006;
public const int WM_NULL = 0x0000;
public const int WM_CREATE = 0x0001;
public const int WM_DESTROY = 0x0002;
public const int WM_MOVE = 0x0003;
public const int WM_SIZE = 0x0005;
public const int WM_SETFOCUS = 0x0007;
public const int WM_MOUSEACTIVATE = 0x0021;
public const int WM_CLOSE = 0x0010;
public const int WM_QUIT = 0x0012;
public const int WM_KEYDOWN = 0x0100;
public const int WM_KEYUP = 0x0101;
public const int WM_CHAR = 0x0102;
public const int WM_DEADCHAR = 0x0103;
public const int WM_SYSKEYDOWN = 0x0104;
public const int WM_SYSKEYUP = 0x0105;
public const int WM_SYSCHAR = 0x0106;
public const int WM_SYSDEADCHAR = 0x0107;
public const int WM_UNICHAR = 0x0109;
public const int WM_KEYLAST = 0x0109;
public const int UNICODE_NOCHAR = 0xFFFF;
public const int MK_LBUTTON = 0x0001;
public const int MK_RBUTTON = 0x0002;
public const int MK_SHIFT = 0x0004;
public const int MK_CONTROL = 0x0008;
public const int MK_MBUTTON = 0x0010;
public const int WM_MOUSEFIRST = 0x0200;
public const int WM_MOUSEMOVE = 0x0200;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_RBUTTONDOWN = 0x0204;
public const int WM_RBUTTONUP = 0x0205;
public const int WM_RBUTTONDBLCLK = 0x0206;
public const int WM_MBUTTONDOWN = 0x0207;
public const int WM_MBUTTONUP = 0x0208;
public const int WM_MBUTTONDBLCLK = 0x0209;
public const int WM_MOUSEWHEEL = 0x020A;
public const int WM_MDICREATE = 0x0220;
public const int WM_ERASEBKGND = 0x14;
public const int WM_PAINT = 0xF;
public const int WM_NC_HITTEST = 0x84;
public const int WM_NC_PAINT = 0x85;
public const int WM_PRINTCLIENT = 0x318;
public const int WM_SETCURSOR = 0x20;
public const int BM_CLICK = 0x00F5;
public const int BM_GETIMAGE = 0x00F6;
public const int BM_SETIMAGE = 0x00F7;
public const int VK_BACK = 0x08;
public const int VK_TAB = 0x09;
public const int VK_CLEAR = 0x0C;
public const int VK_RETURN = 0x0D;
public const int VK_SHIFT = 0x10;
public const int VK_CONTROL = 0x11;
public const int VK_MENU = 0x12;
public const int VK_PAUSE = 0x13;
public const int VK_CAPITAL = 0x14;
public const int VK_KANA = 0x15;
public const int VK_HANGEUL = 0x15;
public const int VK_HANGUL = 0x15;
public const int VK_JUNJA = 0x17;
public const int VK_FINAL = 0x18;
public const int VK_HANJA = 0x19;
public const int VK_KANJI = 0x19;
public const int VK_ESCAPE = 0x1B;
public const int VK_CONVERT = 0x1C;
public const int VK_NONCONVERT = 0x1D;
public const int VK_ACCEPT = 0x1E;
public const int VK_MODECHANGE = 0x1F;
public const int VK_SPACE = 0x20;
public const int VK_PRIOR = 0x21;
public const int VK_NEXT = 0x22;
public const int VK_END = 0x23;
public const int VK_HOME = 0x24;
public const int VK_LEFT = 0x25;
public const int VK_UP = 0x26;
public const int VK_RIGHT = 0x27;
public const int VK_DOWN = 0x28;
public const int VK_SELECT = 0x29;
public const int VK_PRINT = 0x2A;
public const int VK_EXECUTE = 0x2B;
public const int VK_SNAPSHOT = 0x2C;
public const int VK_INSERT = 0x2D;
public const int VK_DELETE = 0x2E;
public const int VK_HELP = 0x2F;
public const int KEYEVENTF_EXTENDEDKEY = 0x0001;
public const int KEYEVENTF_KEYUP = 0x0002;
public const int KEYEVENTF_UNICODE = 0x0004;
public const int KEYEVENTF_SCANCODE = 0x0008;
public const int HC_ACTION = 0x0;
public const int WH_MOUSELL = 0xE;
public const int STATUS_SUCCESS = 0x0;
#endregion
#region API函数声明
[DllImport("user32.dll", EntryPoint = "SetParent")]
public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "GetParent")]
public static extern int GetParent(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int lNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("user32.dll", EntryPoint = "UpdateWindow")]
public static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "keybd_event")]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, long dwExtraInfo);
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern void SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "DrawMenuBar")]
public static extern int DrawMenuBar(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "mouse_event")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);
[DllImport("user32.dll", EntryPoint = "SetCursorPos")]
public static extern void SetCursorPos(int x, int y);
[DllImport("user32.dll", EntryPoint = "GetCursorPos")]
public static extern bool GetCursorPos(out POINT p);
[DllImport("user32.dll", EntryPoint = "SetWindowsHookEx")]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", EntryPoint = "UnhookWindowsHookEx")]
public static extern int UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", EntryPoint = "CallNextHookEx")]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowDC")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(POINT Point);
[DllImport("user32.dll", EntryPoint = "GetDoubleClickTime")]
public static extern int GetDoubleClickTime();
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
#endregion
/// <summary>
/// 表示 Hook 回调函数。
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
/// <summary>
/// 表示进程间传递的数据结构
/// </summary>
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
/// <summary>
/// 用于通过 API 获取位置信息的结构。
/// </summary>
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
/// <summary>
/// 与非托管通信的鼠标位置结构。
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
}
/// <summary>
/// 鼠标事件标识。
/// </summary>
public enum MouseEventFlags
{
Move = 0x0001,
LeftDown = 0x0002,
LeftUp = 0x0004,
RightDown = 0x0008,
RightUp = 0x0010,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
Wheel = 0x0800,
Absolute = 0x8000
}
}
public class FormatSystemDatetime
{
[DllImport("kernel32.dll", EntryPoint = "GetSystemDefaultLCID")]
public static extern int GetSystemDefaultLCID();
[DllImport("kernel32.dll", EntryPoint = "SetLocaleInfoA")]
public static extern int SetLocaleInfo(int Locale, int LCType, string lpLCData);
[DllImport("user32.dll", EntryPoint = "SendMessageTimeout")]
public static extern long SendMessageTimeout(int hWnd, int Msg, int wParam, int lParam, int fuFlags, int uTimeout, ref int lpdwResult);
public const int LOCALE_SSHORTDATE = 0x1F;
public const int LOCALE_SLONGDATE = 0x20;
public const int LOCALE_STIME = 0x1003;
public const int HWND_BROADCAST = 0xFFFF;
public const int WM_SETTINGCHANGE = 0x001A;
public const int SMTO_ABORTIFHUNG = 2;
public void SetDateTimeFormat()
{
try
{
int p = 0;
int x = GetSystemDefaultLCID();
SetLocaleInfo(x, LOCALE_SSHORTDATE, "yyyy-M-d"); //短日期格式
SetLocaleInfo(x, LOCALE_SLONGDATE, "yyyy年M月d日"); //长日期格式
SetLocaleInfo(x, LOCALE_STIME, "H:mm:ss"); //时间格式
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_ABORTIFHUNG, 10, ref p);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
/// <summary>
/// DevExpress
/// </summary>
public class AboutDevCompanion
{
private int Interval;
private bool ResidentMode;
private bool StopCompanion;
private Thread m_Thread;
/// <summary>
/// 按指定的模式创建 <see cref="Wunion.Budget.PowerBasicFramework.AboutDevCompanion"/> 对象实例。
/// <param name="interval">检测Dev注册弹框的时间间隔(以毫秒为单位)。</param>
/// <param name="resident">检测程序是否以常驻模式运行(默认值 true)。</param>
/// </summary>
public AboutDevCompanion(int interval, bool resident = true)
{
Interval = interval;
ResidentMode = resident;
StopCompanion = true;
}
/// <summary>
/// 关闭 DevExpress 控件的注册弹框(如果调用时找到并关闭了DevExpress注册弹框则返回true,否则返回false)。
/// </summary>
/// <returns></returns>
private bool CloseAboutDev()
{
IntPtr devHwnd = WinAPI.FindWindow(null, "About DevExpress");
if (devHwnd != IntPtr.Zero)
{
WinAPI.SendMessage(devHwnd, WinAPI.WM_CLOSE, 0, 0);
return true;
}
return false;