您现在的位置是:网站首页> C#技术
C#经验总结
- C#技术
- 2024-11-24
- 1960人已阅读
C#经验总结
Word控件Spire.Doc 将 Word 转换为 PDF
比较对象是否是一个(String内容相同是一个对象)
C#Post接口时如何忽略掉SSL证书验证或者添加ssl证书
c# URL Protocol 调用 给winform exe传参数
WebClient HttpWebRequest等访问https站点SSL错误处理
关于C#的反射 Assembly.Load这个通过字节流加载dll,如何解决dll所依赖的dll问题
C# async 函数
异步方法通常返回 Task 或 Task<T> 类型
自己的测试代码开始
static public int AA = 100;
static async Task<int> HelloWait()
{
int A=AA;
AA++;
return await Task.Run(() =>
{
// 执行计算密集型任务
Thread.Sleep(5000);
int result = 10+A;
return result;
});
}
private async void button6_Click(object sender, EventArgs e)
{
int A=await HelloWait();
MessageBox.Show(A.ToString());
}
自己的测试代码结束
public async static void GetInfoAsync()
{
Task<bool> task = Task.Run<bool>(() =>
{
Thread.Sleep(10000); //模拟耗时
return true;
});
//以下两种方式
bool taskResult1 = await task; //内部自己执行了GetAwaiter()
bool taskResult = task.GetAwaiter().GetResult(); //自己手动执行Awaiter(), 但是阻塞UI
Console.WriteLine(taskResult);
}
一些异步编程的常用例子
异步读取文件:
public async Task<string> ReadFileAsync(string filePath)
{
using (StreamReader reader = new StreamReader(filePath))
{
return await reader.ReadToEndAsync();
}
}
异步下载网络资源:
public async Task DownloadFileAsync(string url, string outputPath)
{
using (HttpClient client = new HttpClient())
{
byte[] data = await client.GetByteArrayAsync(url);
await File.WriteAllBytesAsync(outputPath, data);
}
}
异步查询数据库:
public async Task<List<Customer>> GetCustomersAsync()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand("SELECT * FROM Customers", connection))
{
using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
List<Customer> customers = new List<Customer>();
while (await reader.ReadAsync())
{
Customer customer = new Customer
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Email = reader.GetString(2)
};
customers.Add(customer);
}
return customers;
}
}
}
}
异步调用Web API:
public async Task<string> GetDataFromApiAsync(string apiUrl)
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(apiUrl);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
异步执行计算密集型任务:
public async Task<int> CalculateResultAsync(int input)
{
return await Task.Run(() =>
{
// 执行计算密集型任务
int result = SomeComplexCalculation(input);
return result;
});
}
一个上传文件的例子
async Task<string> UpFile()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
//添加字符串参数,参数名为qq
//content.Add(new StringContent("123456"), "qq");
string path = "g:\\1.png";// Path.Combine(System.Environment.CurrentDirectory, "1.png");
//添加文件参数,参数名为files,文件名为123.png
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(path));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
content.Add(fileContent, "image", "123.png");
content.Add(new StringContent("chaoneng"), "apiType");
content.Add(new StringContent("14ff9ab178c34097ff171964fdb166f4"), "token");
var requestUri = new Uri("https://www.hualigs.cn/api/upload"); //"https://www.hualigs.cn/api/upload";
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| (SecurityProtocolType)0x300 //Tls11
| (SecurityProtocolType)0xC00; //Tls12
var response = await client.PostAsync(requestUri, content);
string url = "";
if (response.IsSuccessStatusCode)
{
Console.WriteLine("上传成功!");
var result = response.Content.ReadAsStringAsync().Result;
//MessageBox.Show(result);
try
{
Hashtable m_HH = JsonHelper.JsonStrToOBJ<Hashtable>(result);
if (m_HH.ContainsKey("code"))
{
string code = m_HH["code"].ToString();
if (code == "200")
{
if (m_HH.ContainsKey("data"))
{
Hashtable m_dataHH = JsonHelper.OBJToType<Hashtable>(m_HH["data"]);
if (m_dataHH.ContainsKey("url"))
{
Hashtable m_urlHH = JsonHelper.OBJToType<Hashtable>(m_dataHH["url"]);
if (m_urlHH.ContainsKey("distribute"))
{
Console.WriteLine(m_urlHH["distribute"].ToString());
//MessageBox.Show(m_urlHH["distribute"].ToString());
url = m_urlHH["distribute"].ToString();
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
else
{
string str = "错误码:" + code;
if (m_HH.ContainsKey("msg"))
{
str += "," + m_HH["msg"].ToString();
}
MessageBox.Show(str);
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
catch
{
}
}
else
{
MessageBox.Show("上传异常");
}
/*
Task<string> task = Task.Run<string >(() =>
{
return url;
});
*/
return url;
}
async private void button29_Click(object sender, EventArgs e)
{
string str = await UpFile();
MessageBox.Show(str);
}
Task 启动
任务可以赋值立即运行,也可以先由构造函数赋值,之后再调用。
//启用线程池中的线程异步执行
Task t1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("Task启动...");
});
//启用线程池中的线程异步执行
Task t2 = Task.Run(() =>
{
Console.WriteLine("Task启动...");
});
Task t3 = new Task(() =>
{
Console.WriteLine("Task启动...");
});
t3.Start();//启用线程池中的线程异步执行
t3.RunSynchronously();//任务同步执行
Task 等待任务结果,处理结果
Task t1 = Task.Run(() =>
{
Console.WriteLine("Task启动...");
});
Task t2 = Task.Run(() =>
{
Console.WriteLine("Task启动...");
});
//调用WaitAll() ,会阻塞调用线程,等待任务执行完成 ,这时异步也没有意义了
Task.WaitAll(new Task[] { t1, t2 });
Console.WriteLine("Task完成...");
//调用ContinueWith,等待任务完成,触发下一个任务,这个任务可当作任务完成时触发的回调函数。
//为了获取结果,同时不阻塞调用线程,建议使用ContinueWith,在任务完成后,接着执行一个处理结果的任务。
t1.ContinueWith((t) =>
{
Console.WriteLine("Task完成...");
});
t2.ContinueWith((t) =>
{
Console.WriteLine("Task完成...");
});
//调用GetAwaiter()方法,获取任务的等待者,调用OnCompleted事件,当任务完成时触发
//调用OnCompleted事件也不会阻塞线程
t1.GetAwaiter().OnCompleted(() =>
{
Console.WriteLine("Task完成...");
});
t2.GetAwaiter().OnCompleted(() =>
{
Console.WriteLine("Task完成...");
});
Task 任务取消
//实例化一个取消实例
var source = new CancellationTokenSource();
var token = source.Token;
Task t1 = Task.Run(() =>
{
Thread.Sleep(2000);
//判断是否任务取消
if (token.IsCancellationRequested)
{
//token.ThrowIfCancellationRequested();
Console.WriteLine("任务已取消");
}
Thread.Sleep(500);
//token传递给任务
}, token);
Thread.Sleep(1000);
Console.WriteLine(t1.Status);
//取消该任务
source.Cancel();
Console.WriteLine(t1.Status);
Task 返回值
Task<string> t1 = Task.Run(() => TaskMethod("hello"));
t1.Wait();
Console.WriteLine(t1.Result);
public string TaskMethod(string str)
{
return str + " from task method";
}
TransactionScope支持其他数据库
TransactionOptions transactionOption = new TransactionOptions();
//设置事务隔离级别
transactionOption.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead;
// 设置事务超时时间为60秒
transactionOption.Timeout = new TimeSpan(0, 2, 30);
using (TransactionScope tran = new TransactionScope(TransactionScopeOption.RequiresNew, transactionOption))
{
try
{
using (BaseEngineDB m_BaseEngineDB = GetBaseEngineDB(kv.Key))
{
m_BaseEngineDB.SetNoTransaction();
m_BaseEngineDB.XNActSQL(SQLString, out nActCnt);
}
....//其他数据库操作
tran.Complete();
}
catch (Exception e)
{
bRet = false;
Transaction.Current.Rollback();
return false;
}
finally
{
//释放资源
tran.Dispose();
}
}
MySQL的实例代码
public void test()
{
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
try
{
using (TransactionScope scope = new TransactionScope())
{
returnValue = TestA(returnValue, writer);
returnValue = TestB(returnValue, writer);
scope.Complete();
}
}
catch (Exception ex)
{
}
}
private int TestB(int returnValue, System.IO.StringWriter writer)
{
MySqlConnection conn = new MySqlConnection("server=localhost;database=test;user id=root;password=root;port=3307;characterset=utf8;connectiontimeout=72000;");
conn.Open();
// Execute the second command in the second database.
returnValue = 0;
MySqlCommand command2 = new MySqlCommand("Insert tbb (`time`)value ('10:00:00')", conn);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
conn.Close();
return returnValue;
}
private int TestA(int returnValue, System.IO.StringWriter writer)
{
conn = new MySqlConnection("server=localhost;database=test1;user id=root;password=root;port=3307;characterset=utf8;connectiontimeout=72000;");
conn.Open();
// Create the SqlCommand object and execute the first command.
MySqlCommand command1 = new MySqlCommand("Insert tb1 (`Name`, `Value`)value ('ai', '2017-04-26')", conn);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
conn.Close();
return returnValue;
}
Net 2.0下的TransactionScope分布式事务一直在项目中很好地使用着(Sql Server),最近由于数据库改换了Oracle 10g,出现了一个问题,就是TransactionScope事务用不了了,老是报错:“无法加载oramts.dll ”的错误,经过goole下,终于找到了问题所在。那就是我们在安装Oracle的客户端的时候,在“选择安装类型”时,如果默认的“InstantClient”是不会给我们安装“Oracle services For Microsoft Transaction Server”的,所以我们要选择“自定义”安装。然后在可用“产品组件”页面,要选择“Oracle services For Microsoft Transaction Server 10.2.0.1.0”然后安装就ok了
CS-Script
NET Framework时代用过一个叫做CS-Script的东西,感觉还是不错,发现现在也支持.NET Core了
程序基于.NET 5的开发,尝试引用CS-Script包,发现不太好用,一直提示System.Reflection.TargetInvocationException:"Exception has been thrown by the target of an invocation."。支持.NET Core的实际上是CS-Script.Core这个包,安装即可
Install-Package CS-Script.Core
C#脚本引擎 CS-Script 之性能评测
HelloWorld.cs
class HelloWorld
{
public void SayHello()
{
Console.WriteLine("Hello World, from internal!");
}
}
使用程序内部类和使用脚本的性能比较
static void Main(string[] args)
{
CallFromInternal();
CallFromScript();
}
static void CallFromInternal()
{
Console.WriteLine("");
Console.WriteLine("CallFromInternal");
DateTime beginTime = DateTime.Now;
HelloWorld hello = new HelloWorld();
TimeSpan span = DateTime.Now - beginTime;
Console.WriteLine("create instance timespan: {0}", span);
beginTime = DateTime.Now;
hello.SayHello();
span = DateTime.Now - beginTime;
Console.WriteLine("call helloWorld timespan: {0}", span);
}
static void CallFromScript()
{
Console.WriteLine("");
Console.WriteLine("CallFromScript");
DateTime beginTime = DateTime.Now;
dynamic hello = CSScript.Evaluator.LoadFile("HelloWorld.cs");
TimeSpan span = DateTime.Now - beginTime;
Console.WriteLine("load and precompile script file, timespan= {0}", span);
beginTime = DateTime.Now;
hello.SayHello();
span = DateTime.Now - beginTime;
Console.WriteLine("call helloWorld timespan: {0}", span);
}
从以上两个函数的输出结果来看,直接调用程序内部函数的时间大概是2ms,而通过脚本引擎来同样一个HelloWorld的时间就达到了835ms,时间差距有400倍
这是因为第一次要动态编译的时候,程序要将.NET的用于动态编译的程序集(CSharpCodeProvider)加载到内存中,这个过程可能比较花时间,而动态编译本身是很快的
C# 关于打印 - PrintRaw
public class PrintRaw
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOC_INFO_1
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter,
IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level,
[In, MarshalAs(UnmanagedType.LPStruct)] DOC_INFO_1 di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
public void Print(String printerName, String filename)
{
IntPtr lhPrinter;
OpenPrinter(printerName, out lhPrinter, new IntPtr(0));
if (lhPrinter.ToInt32() == 0)
new Exception($"Not find printer [{printerName}]");
var rawPrinter = new DOC_INFO_1() { pDocName = "My Document", pDataType = "RAW" };
StartDocPrinter(lhPrinter, 1, rawPrinter);
using (var b = new BinaryReader(File.Open(filename, FileMode.Open)))
{
var length = (int)b.BaseStream.Length;
const int bufferSize = 8192;
var numLoops = length / bufferSize;
var leftOver = length % bufferSize;
for (int i = 0; i < numLoops; i++)
{
var buffer = new byte[bufferSize];
int dwWritten;
b.Read(buffer, 0, bufferSize);
IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
WritePrinter(lhPrinter, unmanagedPointer, bufferSize, out dwWritten);
Marshal.FreeHGlobal(unmanagedPointer);
}
if (leftOver > 0)
{
var buffer = new byte[leftOver];
int dwWritten;
b.Read(buffer, 0, leftOver);
IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
var result = WritePrinter(lhPrinter, unmanagedPointer, leftOver, out dwWritten);
Marshal.FreeHGlobal(unmanagedPointer);
}
}
EndDocPrinter(lhPrinter);
ClosePrinter(lhPrinter);
}
}
打印机底层驱动的包
函数名称 说明
AbortPrinter 删除打印机的假脱机文件
AddForm 向可被选择用于给定打印机的格式表中添加一
格式
AddJob 返回一个可用来存储打印工作的文件的完整路
径和文件名
AddMonitor 安装一个本机打印机监视器,并连接配置文件
、数据文件和监视器文件
AddPort 向支持的端口列表中添加一端口名
AddPrinter 向指定的服务器所支持的打印机列表中添加一
打印机
AddPrinterConnection 为当前用户添加指定的打印机并连接
AddPrinterDriver 安装一本地或远程打印机并连接培植文件、数
据文件和驱动文件
AddPrintProcessor 在指定的服务器上安装一打印处理程序,并将它
的名称添加到所支持的内部列表中
AddPrintProvidor 安装一本地打印机提供程序,并连接配置文件、
数据文件和提供程序文件
AdvancedDocumentProperties 为给定的打印机显示一个打印机高级配置对话
框,以允许进行配置
ClosePrinter 关闭给定的打印机对象
ConfigurePort 显示指定服务器上给定端口的配置对话框,以
允许进行配置
ConnectToPrinterDlg 显示一对话框供用户在网络浏览并连接打印机
DeleteForm 从所支持的格式表中删除一个格式名
DeleteMonitor 删除一个由AddMonitor函数所添加的打印机监
视器
DeleteProt 显示一对话框,以允许用户删除一个端口名
DeletePrinter 删除指定的打印机对象
DeletePrinterConnection 删除指定的打印机连接
DeletePrinterDriver 从给定服务器所支持的驱动器名称表中删除指
定的打印机驱动器
DeletePrintProcessor 删除由AddPrintProcessor函数所添加的打印机
处理程序
DeletePrintProvidor 删除由AddPrintProvidor函数所添加的提供器
DeviceCapabilities 获取指定的打印机所需求的性能
DocumentProperties 为给定的打印机显示一个打印机配置对话框,
以允许进行配置
EndDocPrinter 终止给定打印机的一个打印作业
EndPagePrinter 指示一页的结束和下一页的开始
EnumForms 枚举指定打印机所支持的格式
EnumJobs 用描述打印机的打印作业数据初始化一个
JOB_INFO_1或JOB_INFO_2结构数组,以便枚举打
印机作业
EnumMonitors 用描述给定服务器的监视器数据初始化一个
MONITOR_INFO_1结构数组,以便枚举打印机监视
器
EnumPorts 枚举可用于在指定服务器上进行打印的端口
EnumPrinterDrivers 枚举在给定打印机服务器上安装的所有打印机
驱动程序
EnumPrinters 枚举指定服务器上可用的打印机
EnumPrintProcessorDatatypes 枚举指定打印机处理程序所支持的数据类型
EnumPrintProcessors 枚举在指定服务器上安装的打印处理器
FindClosePrinterChangeNotification关闭通过调用
FindFirstPrinterChangeNotification函数建
立的改变通知对象
FindFirstPrinterChangeNotification创建一个改变通知对象并返回句柄,使用该
句柄在调用一个等待函数期间,检查打印机或打
印服务器的变化
FindNextPrinterChangeNotification为与指定打印机或打印服务器相关的改变通
知对象检取最近的改变通知通知信息,也可用来
重新设置该改变通知对象为不发信息状态
FreePrinterNotifyInfo 释放系统分配的由
FindNextPrinterChangeNotification函数返回
的缓冲区
GetForm 利用描述给定打印机指定格式的数据初始化一
个FORM_INFO_1结构
GetJob 检取指定打印机的打印作业数据
GetPrinter 检取给定打印机的数据
GetPrinterData 检取给定打印机的配置数据
GetPrinterDriver 检取给定打印机的驱动程序数据
GetPrinterDriverDirectory 检取给定打印机驱动程序的目录路径
GetPrintProcessDirectory 检取指定服务器上打印机处理程序的路径
OpenPrinter 检取一个标识特定打印机或打印服务器的句柄
并打开
PrinterMessageBox 显示一个消息框,供一个正打印的应用程序通知
用户发生一个打印作业错误
PrinterProperties 为给定打印机显示一个打印机性能对话框,以允
许进行设置
ReadPrinter 从给定打印机检取数据
ResetPrinter 让应用程序设定有StartDocPrinter函数提交的
打印文档的数据类型和设备模式值
ScheduleJob 通知假脱机打印程序,可为指定的作业安排打印
SetForm 为给定的打印机设置格式信息
SetJob 暂停,恢复,取消或重新启动给定打印机上指定
的打印作业
SetPrinter 用暂停,恢复,或清除所有打印作业来设置指定
的打印机
SetPrinterData 设置一台打印机的配置数据
StartDocPrinter 通知假脱机打印程序将在假脱机上打印一个文
档
StartPagePrinter 通知假脱机打印程序将在给定打印机上打印一页
WritePrinter 通知假脱机打印程序应向给定的打印机写指定
的数据
用底层的通讯命令,实现很多命令
Word控件Spire.Doc 将 Word 转换为 PDF
Spire.Doc for .NET是一个专业的.NET 库,使用户无需安装Microsoft Word 即可直接管理文字编辑,编辑后,您可以分两步将文档转换为PDF。
在线文档:https://www.e-iceblue.cn/spiredoc/spire-doc-for-net-program-guide-content.html
账户 hellopdf hellopdf
VB代码
Imports System
Imports Spire.Doc
Imports Spire.Doc.Documents
Namespace DoctoPDF
Friend Class toPDF
Shared Sub Main(ByVal args() As String)
'Load Document
Dim document As New Document()
document.LoadFromFile("E:\work\documents\TestSample.docx")
'Convert Word to PDF
document.SaveToFile("toPDF.PDF", FileFormat.PDF)
'Launch Document
System.Diagnostics.Process.Start("toPDF.PDF")
End Sub
End Class
End Namespace
C#代码
using Spire.Doc;
using Spire.Pdf.Security;
namespace WordToPDFAndEncrypt_PDF
{
class Program
{
static void Main(string[] args)
{
//加载Word测试文档
Document doc = new Document();
doc.LoadFromFile("test.docx");
//转为PDF时,设置PDF打开密码和权限密码
ToPdfParameterList topdf = new ToPdfParameterList();
topdf.PdfSecurity.Encrypt("open", "permission", PdfPermissionsFlags.Print | PdfPermissionsFlags.CopyContent, PdfEncryptionKeySize.Key128Bit);
//将文档保存为PDF格式
doc.SaveToFile("result.pdf", topdf);
System.Diagnostics.Process.Start("result.pdf");
}
}
}
C#调用C++ DLL
DLL编译的时候需要指定系统版本x64或者x86,所以在接入dll的时候需要明确产品定位,具体接入那个版本库,x86系统不支持x64软件,x64可以运行x86(好像有性能损耗)。
C++里头文件定义形势如下:
typedef void (*CALLBACKFUN1W)(wchar_t*, void* pArg);
typedef void (*CALLBACKFUN1A)(char*, void* pArg);
bool BIOPRINT_SENSOR_API dllFun1(CALLBACKFUN1 pCallbackFun1, void* pArg);
在其中一个导入的dll方法里,有一个回调函数的参数
[DllImport("test.dll", EntryPoint = "dllFunc1", CharSet = CharSet.Unicode)]
public static extern bool dllFunc1([MarshalAs(UnmanagedType.FunctionPtr)] CallbackFunc1 pCallbackFunc1 , IntPtr pArg);
回调函数在C#里定义成委托如下:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackFunc1([MashalAs(UnmanagedType.LPWStr)] StringBuilder strName, IntPtr pArg);
而系统默认方式为 CallingConvention.StdCall。
典型使用例子
C++里的定义
struct OneQF //点击查看在C#中定义
{
char RCVBL_AMT_ID[17];// VARCHAR2(16) 应收电费标识
char RCVBL_YM[7];// VARCHAR2(6) 应收年月
int OWE_AMT;// NUMBER(18) 本次应缴电费金额
int RCVBL_PENALTY;// NUMBER(18) 本次应缴违约金
char REMARK[65];//;// VARCHAR2(64) 描述本条欠费的其它信息(可以为空)
};
struct AskQFReturn //查询欠费返回,点击查看在 C#中定义
{
BOOL bOK;
char RETURN_CODE[5];
char RETURN_MSG[129];
char BATCH_NO[33];//电力资金编号
char ORG_NO[17];//电力资金结算单位编号
char CONS_NO[33];// 用户编号
char TRANS_NAME[65];// 用户名称
char ELEC_ADDR[129];// VARCHAR2(128) 用电地址
char ORG_NAME[65];// VARCHAR2(64) 用户供电单位名称
int EXCHG_AMT;// NUMBER(18) 本次应缴总电费(等于明细中"本次应缴电费金额 + 本次应缴违约金")
int PREPAY_BAL; //NUMBER(18) 余额(余额与欠费一般不会同时出现,不作为缴费依据)
int TOTAL_AMT;//需要写的金额
char TOTAL_AMTMEMO[256];//需要写的金额描述
int COUNT;// INT 记录数
struct OneQF m_OneQFArray[12];
};
extern BOOL WINAPI WEB_AskQF(char *sWDBM,char *sCZNO,char *sIndex,char *sKHNO,struct AskQFReturn *pAskQFReturn)
C#里定义
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct OneQF //点击查看他在 C++定义
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string RCVBL_AMT_ID;//[17];// VARCHAR2(16) 应收电费标识
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
public string RCVBL_YM;//[7];// VARCHAR2(6) 应收年月
public int OWE_AMT;// NUMBER(18) 本次应缴电费金额
public int RCVBL_PENALTY;// NUMBER(18) 本次应缴违约金
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string REMARK;//[65];//;// VARCHAR2(64) 描述本条欠费的其它信息(可以为空)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AskQFReturn //查询欠费返回,点击查看他在C++中定义
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string BATCH_NO;//[33];//电力资金编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string ORG_NO;//[17];//电力资金结算单位编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string CONS_NO;//[33];// 用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string TRANS_NAME;//[65];// 用户名称
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string ELEC_ADDR;//[129];// VARCHAR2(128) 用电地址
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string ORG_NAME;//[65];// VARCHAR2(64) 用户供电单位名称
public int EXCHG_AMT;// NUMBER(18) 本次应缴总电费(等于明细中"本次应缴电费金额 + 本次应缴违约金")
public int PREPAY_BAL; //NUMBER(18) 余额(余额与欠费一般不会同时出现,不作为缴费依据)
public int TOTAL_AMT;//需要买的最小金额分
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string TOTAL_AMTMEMO;//[65];// VARCHAR2(64) 需要买的最小金额描述
public int COUNT;// INT 记录数
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public OneQF[] m_OneQFArray;//[12];
};
[DllImport("PowerDll.dll", EntryPoint = "WEB_AskQF",CharSet = CharSet.Ansi)]
public static extern bool WEB_AskQF(string sWDBM, string sCZNO, string sIndex, string sKHNO, ref AskQFReturn m_AskQFReturn);
调用:
AskQFReturn m_AskQFReturn = new AskQFReturn();
m_AskQFReturn.m_OneQFArray = new OneQF[12];
int i;
IntPtr[] m_STArray = new IntPtr[12];
for (i = 0; i < 12; i++)
{
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WBS.OneInQF)) * 1);
m_STArray[i] = p;
m_AskQFReturn.m_OneQFArray[i] = (WBS.OneQF)Marshal.PtrToStructure(p, typeof(WBS.OneQF));
if (i >= m_AskQFReturn.COUNT)
{
continue;
}
}
string sIndex = GetLSNO();
if (WEB_AskQF(m_MNSession.sDZWDBM, m_MNSession.sDZCZNO, sIndex, m_RawAskCB.yhhao, ref m_AskQFReturn))
{
。。。
}
//释放内存
for (i = 0; i < 12; i++)
{
Marshal.FreeHGlobal(m_STArray[i]);
}
实际项目中使用
C++代码
导出函数PowerDll.def内容
; PowerDll.def : Declares the module parameters for the DLL.
LIBRARY "PowerDll"
DESCRIPTION 'PowerDll Windows Dynamic Link Library'
EXPORTS
; Explicit exports can go here
WEB_SetPowerPZ
WEB_SetPowerPZ2
WEB_AskQF
WEB_PutInQF
WEB_RestorePutInQF
WEB_AskPowerCard
WEB_BuyPowerCard
WEB_RestoreBuyPowerCard
WEB_BXCard
WEB_AskTicket
WEB_PowerDZ
MAC
WEB_AskBuyPowerState
WEB_FeedBackBXCard
WEB_AskWaitWriteCard
WEB_AskWriteCardOver
WEB_AskQF2
WEB_AskWriteCardOver2
WEB_AskWriteCardOver3
// PowerDll.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include <afxdllx.h>
#include "..\电力服务核心文件\PowerNetLayer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static AFX_EXTENSION_MODULE PowerDllDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("POWERDLL.DLL Initializing!\n");
::InitializeCriticalSection(&XSocketBase::CS);
::InitializeCriticalSection(&XSocketBase::m_DLCS);
::InitializeCriticalSection(&XSocketBase::m_CXCS);
::InitializeCriticalSection(&XSocketBase::m_BuyCS);
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(PowerDllDLL, hInstance))
return 0;
// Insert this DLL into the resource chain
// NOTE: If this Extension DLL is being implicitly linked to by
// an MFC Regular DLL (such as an ActiveX Control)
// instead of an MFC application, then you will want to
// remove this line from DllMain and put it in a separate
// function exported from this Extension DLL. The Regular DLL
// that uses this Extension DLL should then explicitly call that
// function to initialize this Extension DLL. Otherwise,
// the CDynLinkLibrary object will not be attached to the
// Regular DLL's resource chain, and serious problems will
// result.
InitializeCriticalSection(&PowerNetLayer::CS);
new CDynLinkLibrary(PowerDllDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("POWERDLL.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(PowerDllDLL);
}
return 1; // ok
}
extern CString sGlobalQDNO,sGlobalKey,sGlobalSYSNO;
extern BOOL WINAPI WEB_AskQF(char *sWDBM,char *sCZNO,char *sIndex,char *sKHNO,struct AskQFReturn *pAskQFReturn)
{
return PowerNetLayer::APP_AskQF(sWDBM,sCZNO,sIndex,sKHNO,pAskQFReturn);
}
extern BOOL WINAPI WEB_PutInQF(char *sWDBM,char *sCZNO,char *sIndex,char * BATCH_NO,struct PutInQF *pPutInQF,struct PutInQFReturn *pPutInQFReturn)
{
return PowerNetLayer::APP_PutInQF(sWDBM,sCZNO,sIndex,BATCH_NO,pPutInQF,pPutInQFReturn);
}
extern BOOL WINAPI WEB_RestorePutInQF(char *sWDBM,char *sCZNO,char *sIndex, RestorePutInQF *pRetorePutInQF, RestorePutInQFReturn *pRestorePutInQFReturn)
{
return PowerNetLayer::APP_RestorePutInQF(sWDBM,sCZNO, sIndex, pRetorePutInQF, pRestorePutInQFReturn);
}
//卡表
extern BOOL WINAPI WEB_AskPowerCard(char *sWDBM,char *sCZNO,char *sIndex,AskPowerCard *pAskPowerCard,AskPowerCardReturn *pAskPowerCardReturn)
{
return PowerNetLayer::APP_AskPowerCard(sWDBM,sCZNO,sIndex,pAskPowerCard,pAskPowerCardReturn);
}
extern BOOL WINAPI WEB_BuyPowerCard(char *sWDBM,char *sCZNO,char *sIndex,BuyPowerCard *pBuyPowerCard,BuyPowerCardReturn *pBuyPowerCardReturn)
{
return PowerNetLayer::APP_BuyPowerCard(sWDBM,sCZNO,sIndex,pBuyPowerCard,pBuyPowerCardReturn);
}
extern BOOL WINAPI WEB_RestoreBuyPowerCard(char *sWDBM,char *sCZNO,char *sIndex,RestoreBuyPowerCard *pRestoreBuyPowerCard,RestoreBuyPowerCardReturn *pRestoreBuyPowerCardReturn)
{
return PowerNetLayer::APP_RestoreBuyPowerCard(sWDBM,sCZNO,sIndex,pRestoreBuyPowerCard,pRestoreBuyPowerCardReturn);
}
extern BOOL WINAPI WEB_BXCard(char *sWDBM,char *sCZNO,char *sIndex,BXCard *pBXCard,BXCardReturn *pBXCardReturn)
{
return PowerNetLayer::APP_BXCard( sWDBM,sCZNO,sIndex,pBXCard,pBXCardReturn);
}
extern BOOL WINAPI WEB_AskTicket(char *sWDBM,char *sCZNO,char *sIndex,AskTicket *pAskTicket,AskTicketReturn *pAskTicketReturn)
{
return PowerNetLayer::APP_AskTicket( sWDBM,sCZNO,sIndex,pAskTicket,pAskTicketReturn);
}
//对账户
extern BOOL WINAPI WEB_PowerDZ(char *sWDBM,char *sCZNO,char *sIndex,PowerDZ *pPowerDZ,PowerDZReturn *pPowerDZReturn)
{
return PowerNetLayer::APP_PowerDZ(sWDBM,sCZNO, sIndex,pPowerDZ,pPowerDZReturn);
}
extern void WINAPI WEB_SetPowerPZ(char *sQDNO0,char *sKey0,char *sSYSNO0)
{
sGlobalQDNO.Format("%s",sQDNO0);
sGlobalKey.Format("%s",sKey0);
sGlobalSYSNO.Format("%s",sSYSNO0);
}
extern void WINAPI WEB_SetPowerPZ2(char *sDLIP,char *sPort,char *sQDNO0,char *sKey0,char *sSYSNO0)
{
PowerNetLayer::nPort=atoi(sPort);
sprintf(PowerNetLayer::sIP,"%s",sDLIP);
sGlobalQDNO.Format("%s",sQDNO0);
sGlobalKey.Format("%s",sKey0);
sGlobalSYSNO.Format("%s",sSYSNO0);
CString sMsg;
sMsg.Format("设置IP:%s,端口:%d",PowerNetLayer::sIP,PowerNetLayer::nPort);
XSocketBase::WriteLog(sMsg);
}
extern CString MAC()
{
/*
0106046045
0120575973
0120541921
缴费的用0151481925
*/
/*
struct AskQFReturn *pAskQFReturn=new struct AskQFReturn;
PowerNetLayer::APP_AskQF(1,"0151481925",pAskQFReturn);
delete pAskQFReturn;
return "";
*/
// CString Str=MACAction::GetMAC("200001|compcode|20120521125152|1205250957011|spot_code|abc123|01|1401978481|201205|20120512|","1234567890ABCDEF");
/*
GenKeyMac m_GenKeyMac;
BYTE Key[]={0x12,0x34,0x56,0x78,0x90,0xAB,0xCD,0xEF};
BYTE Out[256];
CString strInput="200001COMPCODE201205211251521205250957011SPOTCODEABC12301140197848120120520120512";
CString m_strOutput = MD5String((char*)(LPCTSTR)strInput);
BYTE *pData=(BYTE *)(const char *)m_strOutput;
CString AllStr,TStr;
BYTE S[8];
for(int i=0;i<8;i++)
{
BYTE A=GetBYTE(pData+i*2);
BYTE B=GetBYTE(pData+16+i*2);
A=A^B;
if(A<15)
TStr.Format("0%x",A);
else
TStr.Format("%x",A);
AllStr+=TStr;
S[i]=A;
}
m_GenKeyMac.MyDes(S,Key,Out,ENCRYPT);
return ByteToStr(Out,8);
*/
return "";
}
extern BOOL WINAPI WEB_AskBuyPowerState(char *sWDBM,char *sCZNO,char *sIndex,AskPowerJYState *pAskPowerJYState,AskPowerJYStateReturn *pAskPowerJYStateReturn)
{
return PowerNetLayer::APP_AskBuyPowerState(sWDBM,sCZNO,sIndex,pAskPowerJYState,pAskPowerJYStateReturn);
}
extern BOOL WINAPI WEB_FeedBackBXCard(char *sWDBM,char *sCZNO,char *sIndex,FeedBackBXCard *pFeedBackBXCard,FeedBackBXCardReturn *pFeedBackBXCardReturn)
{
return PowerNetLayer::APP_FeedBackBXCard( sWDBM, sCZNO,sIndex,pFeedBackBXCard,pFeedBackBXCardReturn);
}
extern BOOL WINAPI WEB_AskWaitWriteCard(char *sWDBM,char *sCZNO, char *sIndex,AskWaitWriteCard *pAskWaitWriteCard,AskWaitWriteCardReturn *pAskWaitWriteCardReturn)
{
return PowerNetLayer::APP_AskWaitWriteCard(sWDBM,sCZNO, sIndex,pAskWaitWriteCard,pAskWaitWriteCardReturn);
}
extern BOOL WINAPI WEB_AskWriteCardOver(char *sWDBM,char *sCZNO, char *sIndex,AskWriteCardOver *pAskWriteCardOver,AskWriteCardOverReturn *pAskWriteCardOverReturn)
{
if(PowerNetLayer::APP_AskWriteCardOver(sWDBM,sCZNO, sIndex,pAskWriteCardOver,pAskWriteCardOverReturn))
{
CString TStr,AllStr;
AllStr.Format("最少购买金额:%.2f", pAskWriteCardOverReturn->TOTAL_AMT/100.);
int i;
for(i=0;i<pAskWriteCardOverReturn->COUNT;i++)
{
TStr.Format("%s:%.2f元",pAskWriteCardOverReturn->m_OneFYArray[i].RCV_TYPE,pAskWriteCardOverReturn->m_OneFYArray[i].RCV_AMT/100.);
if(AllStr!="")
{
AllStr+="\r\n";
}
AllStr+=TStr;
}
sprintf(pAskWriteCardOverReturn->TOTAL_AMTMEMO,"%s",(char *)(const char *)AllStr);
return pAskWriteCardOverReturn->bOK;
}
return false;
}
extern BOOL WINAPI WEB_AskQF2(char *sWDBM,char *sCZNO,char *sIndex1,char *sKHNO, char *sIndex2,struct AskQFReturn *pAskQFReturn)
{
if(!PowerNetLayer::APP_AskQF(sWDBM,sCZNO,sIndex1,sKHNO,pAskQFReturn))
{
return false;
}
else
{
AskWaitWriteCard m_AskWaitWriteCard;
AskWaitWriteCardReturn m_AskWaitWriteCardReturn;
sprintf(m_AskWaitWriteCard.CONS_NO,pAskQFReturn->CONS_NO);
if(!WEB_AskWaitWriteCard(sWDBM,sCZNO,sIndex2,&m_AskWaitWriteCard,&m_AskWaitWriteCardReturn))
{
pAskQFReturn->bOK=false;
sprintf(pAskQFReturn->RETURN_CODE,"%s",m_AskWaitWriteCardReturn.RETURN_CODE);
sprintf(pAskQFReturn->RETURN_MSG,"%s",m_AskWaitWriteCardReturn.RETURN_MSG);
return false;
}
else
{
pAskQFReturn->TOTAL_AMT=m_AskWaitWriteCardReturn.TOTAL_AMT;//分
CString TStr,AllStr;
if(pAskQFReturn->TOTAL_AMT<0)
AllStr.Format("最少购买金额:%.2f", -pAskQFReturn->TOTAL_AMT/100.);
else
{
AllStr.Format("卡总金额:%.2f", pAskQFReturn->TOTAL_AMT/100.);
}
int i;
for(i=0;i<m_AskWaitWriteCardReturn.COUNT;i++)
{
TStr.Format("%s:%.2f元",m_AskWaitWriteCardReturn.m_OneFYArray[i].RCV_TYPE,m_AskWaitWriteCardReturn.m_OneFYArray[i].RCV_AMT/100.);
if(AllStr!="")
{
AllStr+="\r\n";
}
AllStr+=TStr;
}
sprintf(pAskQFReturn->TOTAL_AMTMEMO,"%s",(char *)(const char *)AllStr);
return true;
}
}
}
extern BOOL WINAPI WEB_AskWriteCardOver2(char *sWDBM,char *sCZNO, char *sIndex,char *CONS_NO,char *PURCHASE_ID)
{
AskWriteCardOver m_AskWriteCardOver;
sprintf(m_AskWriteCardOver.CONS_NO,"%s",CONS_NO);
sprintf(m_AskWriteCardOver.PURCHASE_ID,"%s",PURCHASE_ID);
AskWriteCardOverReturn m_AskWriteCardOverReturn;
if(WEB_AskWriteCardOver(sWDBM,sCZNO, sIndex,&m_AskWriteCardOver,&m_AskWriteCardOverReturn))
{
return m_AskWriteCardOverReturn.bOK;
}
else
return false;
}
extern BOOL WINAPI WEB_AskWriteCardOver3(char *sWDBM,char *sCZNO, char *sIndex,char *CONS_NO,char *PURCHASE_ID,AskWriteCardOver3Return *pAskWriteCardOver3Return)
{
AskWriteCardOver m_AskWriteCardOver;
sprintf(m_AskWriteCardOver.CONS_NO,"%s",CONS_NO);
sprintf(m_AskWriteCardOver.PURCHASE_ID,"%s",PURCHASE_ID);
AskWriteCardOverReturn m_AskWriteCardOverReturn;
if(WEB_AskWriteCardOver(sWDBM,sCZNO, sIndex,&m_AskWriteCardOver,&m_AskWriteCardOverReturn))
{
int i;
CString AllStr="";
CString TStr;
pAskWriteCardOver3Return->bOK=m_AskWriteCardOverReturn.bOK;
for(i=0;i<m_AskWriteCardOverReturn.COUNT;i++)
{
TStr.Format("%s:%.2f元",m_AskWriteCardOverReturn.m_OneFYArray[i].RCV_TYPE,m_AskWriteCardOverReturn.m_OneFYArray[i].RCV_AMT/100.);
if(AllStr!="")
{
AllStr+="\r\n";
}
AllStr+=TStr;
}
sprintf(pAskWriteCardOver3Return->RETURN_CODE,"%s",m_AskWriteCardOverReturn.RETURN_CODE);
sprintf(pAskWriteCardOver3Return->RETURN_MSG,"%s",m_AskWriteCardOverReturn.RETURN_MSG);
sprintf(pAskWriteCardOver3Return->ELEC_ADDR,"%s",m_AskWriteCardOverReturn.ELEC_ADDR);
sprintf(pAskWriteCardOver3Return->TOTAL_AMTMEMO,"%s",(char *)(const char *)AllStr);
pAskWriteCardOver3Return->TOTAL_AMT=m_AskWriteCardOverReturn.TOTAL_AMT;
return m_AskWriteCardOverReturn.bOK;
}
else
{
pAskWriteCardOver3Return->bOK=m_AskWriteCardOverReturn.bOK;
sprintf(pAskWriteCardOver3Return->RETURN_CODE,"%s",m_AskWriteCardOverReturn.RETURN_CODE);
sprintf(pAskWriteCardOver3Return->RETURN_MSG,"%s",m_AskWriteCardOverReturn.RETURN_MSG);
return false;
}
}
extern BOOL WINAPI WEB_AskCONS(char *sWDBM,char *sCZNO,char *sIndex1,char *sKHNO, char *sIndex2,struct AskCONSReturn *pAskCONSReturn)
{
return false;
//return PowerNetLayer::APP_AskCONS(sWDBM,sCZNO,sIndex,sKHNO,pAskCONSReturn);
}
C#代码
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
//电力功能开始
public struct OneQF2
{
public string RCVBL_AMT_ID;//[17];// VARCHAR2(16) 应收电费标识
public string RCVBL_YM;//[7];// VARCHAR2(6) 应收年月
public int OWE_AMT;// NUMBER(18) 本次应缴电费金额
public int RCVBL_PENALTY;// NUMBER(18) 本次应缴违约金
public string REMARK;//[65];//;// VARCHAR2(64) 描述本条欠费的其它信息(可以为空)
};
public struct AskQFReturn2 //查询欠费返回
{
public bool bOK;
public string RETURN_CODE;//[5];
public string RETURN_MSG;//[129];
public string BATCH_NO;//[33];//电力资金编号
public string ORG_NO;//[17];//电力资金结算单位编号
public string CONS_NO;//[33];// 用户编号
public string TRANS_NAME;//[65];// 用户名称
public string ELEC_ADDR;//[129];// VARCHAR2(128) 用电地址
public string ORG_NAME;//[65];// VARCHAR2(64) 用户供电单位名称
public int EXCHG_AMT;// NUMBER(18) 本次应缴总电费(等于明细中"本次应缴电费金额 + 本次应缴违约金")
public int PREPAY_BAL; //NUMBER(18) 余额(余额与欠费一般不会同时出现,不作为缴费依据)
public int TOTAL_AMT;//需要买的最小金额
public string TOTAL_AMTMEMO;
public int COUNT;// INT 记录数
public OneQF2[] m_OneQFArray;//[12];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct OneInQF
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string RCVBL_AMT_ID;//[17];// VARCHAR2(16) 应收电费标识
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
public string RCVBL_YM;//[7];// VARCHAR2(6) 应收年月
public int OWE_AMT;// NUMBER(18) 本次应缴电费
public int RCVBL_PENALTY;// NUMBER(18) 本次应缴违约金
public int RCVED_AMT;// NUMBER(18) 本次实收金额(<=本次应缴电费 +本次应缴违约金)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PutInQF //欠费缴费
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string CONS_NO;//[33];//用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string ORG_NO;//[17];//电力资金结算单位编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string BATCH_NO;//[33];//电力资金编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string ORDER_NO;//[33];//订单编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string PAY_MODE;//[9];//缴费方式
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string SETTLE_MODE;//[9];//支付方式
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
public string BANK_PAY_MODE;//[3];//银行缴费方式
public int RCV_AMT;//交易金额(如果交易金额大于sum(本次应缴电费 +本次应缴违约金))则进预收。
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string BANK_ACCT_DATE;//[9];//账务日期
public int COUNT;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public OneInQF[] m_OneInQFArray;//[12];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PutInQF2 //欠费缴费
{
public string CONS_NO;//[33];//用户编号
public string ORG_NO;//[17];//电力资金结算单位编号
public string BATCH_NO;//[33];//电力资金编号
public string ORDER_NO;//[33];//订单编号
public string PAY_MODE;//[9];//缴费方式
public string SETTLE_MODE;//[9];//支付方式
public string BANK_PAY_MODE;//[3];//银行缴费方式
public int RCV_AMT;//交易金额(如果交易金额大于sum(本次应缴电费 +本次应缴违约金))则进预收。
public string BANK_ACCT_DATE;//[9];//账务日期
public int COUNT;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PutInQFReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct RestorePutInQF
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string CONS_NO;//[33];// VARCHAR2(32) 用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string OLD_SERIAL_NO;//[17];// VARCHAR2(16) 原交易流水(当时缴费时候的那笔流水)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string BANK_ACCT_DATE;//[9];// VARCHAR2(8) 银行账务日期(银行的账务日期)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct RestorePutInQFReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AskPowerCard//查询卡表信息
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 91)]
public string FILE1;// VARCHAR2(90) 购电卡信息文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string FILE2;// VARCHAR2(16) 钱包文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE3;// VARCHAR2(256) 费率文件1
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE4;// VARCHAR2(256) 费率文件2
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 99)]
public string FILE5;//[99];// VARCHAR2(98) 返写区文件(从卡内获取)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AskPowerCardReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string BATCH_NO;//[33];// VARCHAR2(32) 资金结算编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string ORG_NO;//[17];// VARCHAR2(16) 资金结算单位编码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string ORG_NAME;//[65];// VARCHAR2(64) 用户供电单位名称
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CONS_NO;//[17];// VARCHAR2(16) 用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string CONS_NAME;//[65];// VARCHAR2(64) 用户名称
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string PRICE;//[11];// NUMBER(10,6) 综合电价
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string J_PRICE;//[11];// NUMBER(10,6) 尖电价
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string F_PRICE;//[11];// NUMBER(10,6) 峰电价
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string P_PRICE;//[11];// NUMBER(10,6) 平电价
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string G_PRICE;//[11];// NUMBER(10,6) 谷电价
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string METER_TYPE;//[8];//VARCHAR2(8) 卡表类型-卡表类型在对账文件中体现(00 费控 01 量控)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
public string PRE_PQ;//[19];// NUMBER(18) 预置金额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
public string DOWN_BUY_PQ;//[19];// NUMBER(18) 购电金额上限
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
public string UP_BUY_PQ;//[19];// NUMBER(18) 购电金额下限
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
public string CARD_NO;//[33];// VARCHAR2(32) 电卡编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string BUY_NUM;//[9];// VARCHAR2(8) 购电次数(上次购电)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
public string PREPAYBAL;//[19];// NUMBER(18) 调尾金额(网省特殊)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string METER_ID;//[17];// VARCHAR2(16) 电能表标识
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
public string PRE_AMT;//[19];// NUMBER(18) 用户余额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
public string IF_METER;//[2];// VARCHAR2(1) 是否插表(0未插表1已插表)营销通过与卡中次数与数据厍中存储的次数比较后得出)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct BuyPowerCard
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CONS_NO;//[17];// VARCHAR2(16) 用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string PAY_MODE;//[9];// VARCHAR2(8) 缴费方式(金融机构代收0201 非金融机构代收0301)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string SETTLE_MODE;//[9];// VARCHAR2(8) 支付方式(09转账)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
public string BANK_PAY_MODE;//[3];// VARCHAR2(2) 银行缴费方式(01柜台、02 POS、03网银、04电话银行)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string BATCH_NO;//[17];// VARCHAR2(16) 资金结算编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string BANK_ACCT_DATE;//[9];// VARCHAR2(8) 银行账务日期(银行的账务日期)
public int RCV_AMT;// NUMBER(18) 交易金额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string READ_CARD_INFO;//[257];// VARCHAR2(256) 卡表密文信息(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CARD_SERIAL_NO;//[17]; //VARCHAR2(16) 用户卡序号(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CARD_RANDOM_NO;//[17]; //VARCHAR2(16) 用户卡随机数(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string METER_ID;//[17];// VARCHAR2(16) 电能表标识
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct BuyPowerCardReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string PURP_TIMES;//[9];// VARCHAR2(8) 购电次数
public int WRITE_AMT;// NUMBER(18) 写卡金额
public int PRE_AMT;// NUMBER(18) 用户余额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 99)]
public string FILE1;//[99];// VARCHAR2(98) 购电卡信息文件+购电卡信息文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string FILE2;//[25];// VARCHAR2(24) 钱包文件+钱包文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 265)]
public string FILE31;//[265];// VARCHAR2(264) 费率文件1第一部分+费率文件1第一部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 269)]
public string FILE32;//[269];// VARCHAR2(268) 费率文件1第二部分+费率文件1第二部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 265)]
public string FILE41;//[265];// VARCHAR2(264) 费率文件2第一部分+费率文件2第一部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 269)]
public string FILE42;//[269];// VARCHAR2(268) 费率文件2第二部分+费率文件2第二部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 107)]
public string FILE5;//[107];// VARCHAR2(106) 返写文件+返写文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY1;//[17];// VARCHAR2(16) 身份认证密文
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY2;//[17];// VARCHAR2(16) 权限认证密文
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY3;//[17];// VARCHAR2(16) 购电外部认证密文
};
/*
银行售电写卡后如未收到营销反馈或银行操作失误需要回写购电卡信息时调用此交易。
银行读卡后将购电卡信息及原交易流水发送给营销系统,营销系统根据原交易流水对预收费记录进行冲正处理,
并将成功或失败结果反馈给银行。
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct RestoreBuyPowerCard
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CONS_NO;//[17];// VARCHAR2(16) 用户编号
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string BANK_ACCT_DATE;//[9];// VARCHAR2(8) 银行账务日期(银行的账务日期)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string OLD_SERIAL_NO;//[17];// VARCHAR2(16) 原交易流水
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string METER_ID;//[17];// VARCHAR2(16) 电能表标识(用于营销核对)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 91)]
public string FILE1;//[91];// VARCHAR2(90) 购电卡信息文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string FILE2;//[17];// VARCHAR2(16) 钱包文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE3;//[257];// VARCHAR2(256) 费率文件1
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE4;//[257];// VARCHAR2(256) 费率文件2
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 99)]
public string FILE5;//[99];// VARCHAR2(98) 返写区文件(从卡内获取)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct RestoreBuyPowerCardReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];//VARCHAR2(4) 结果代码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
public string IF_PURP;//[2];// VARCHAR2(1) 是否需要回写购电卡(0否1是)
};
/*
4.5.8 IC_01_08/补写卡信息查询
4.5.8.1 功能描述
查询并返回冲正或补写卡时的写卡信息;如果为冲正则返回前一次写卡信息;如果为补写卡则返回最近一次写卡信息。
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct BXCard
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string QUERY_TYPE;//[9];// VARCHAR2(8) 查询类型(01冲正时查询前一次写卡信息;02补写卡时查询最近一次写卡信息)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 91)]
public string FILE1;//[91];// VARCHAR2(90) 购电卡信息文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string FILE2;//[17];// VARCHAR2(16) 钱包文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE3;//[257];// VARCHAR2(256) 费率文件1
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string FILE4;//[257];// VARCHAR2(256) 费率文件2
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 99)]
public string FILE5;//[99];// VARCHAR2(98) 返写区文件(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string READ_CARD_INFO;//[257];// VARCHAR2(256) 卡表密文信息(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CARD_SERIAL_NO;//[17];// VARCHAR2(16) 用户卡序号(从卡内获取)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CARD_RANDOM_NO;//[17];// VARCHAR2(16) 用户卡随机数(从卡内获取)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct BXCardReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];//VARCHAR2(4) 结果代码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string PURP_TIMES;//[9];// VARCHAR2(8) 购电次数
public int WRITE_AMT;// NUMBER(18) 写卡金额
// public int PRE_AMT;// NUMBER(18) 用户余额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 99)]
public string FILE1;//[99];// VARCHAR2(98) 购电卡信息文件+购电卡信息文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string FILE2;//[25];// VARCHAR2(24) 钱包文件+钱包文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 265)]
public string FILE31;//[265];// VARCHAR2(264) 费率文件1第一部分+费率文件1第一部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 269)]
public string FILE32;//[269];// VARCHAR2(268) 费率文件1第二部分+费率文件1第二部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 265)]
public string FILE41;//[265];// VARCHAR2(264) 费率文件2第一部分+费率文件2第一部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 269)]
public string FILE42;//[269];// VARCHAR2(268) 费率文件2第二部分+费率文件2第二部分MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 107)]
public string FILE5;//[107];// VARCHAR2(106) 返写文件+返写文件MAC值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY1;//[17];// VARCHAR2(16) 身份认证密文
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY2;//[17];// VARCHAR2(16) 权限认证密文
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string SKEY3;//[17];// VARCHAR2(16) 购电外部认证密文
};
/*
4.5.9 IC_01_09/缴费票据查询
4.5.9.1 功能描述
查询本次的需要打印的缴费票据信息
银行在收费完成之后,如果需要打印票据调用此交易。银行把本次缴费的交易流水号发给营销系统,
营销系统反馈需要打印的票据类型和票据信息说明。
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AskTicket
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string PAY_SERIAL_NO;//[17];// VARCHAR2(16) 缴费交易流水号(对应于本次电费收缴的交易流水号)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct OneTicket
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string PRINT_ID;//[17];// VARCHAR2(16) 票据标识
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
public string PRINT_TYPE;//[2];// VARCHAR2(1) 票据类型(1:发票,2:收据)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string PRINT_MSG;//[129];// VARCHAR2(128) 票据信息说明(逐张描述,拼装字符串。展示内容由营销系统定,如打印发票的户号、月份、金额等)
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AskTicketReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];//VARCHAR2(4) 结果代码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
public int COUNT;// INT 发票张数
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public OneTicket[] m_OneTicketArray;//=new OneTicket[10];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PowerDZ
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
public string PAY_CLASSIFY;//[3];// VARCHAR2(2) 缴费分类(01:后付费、02 预付费)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string ORG_NO;//[17];// VARCHAR2(16) 电力资金结算单位
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string FILE_NAME;//[129];// VARCHAR2(128) 文件名
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PowerDZReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct FeedBackBXCard
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string PURCHASE_ID;//[15]VARCHAR2(14) 营销返回的ID(补写卡中返回的RETURN_MSG字段)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string STATUS;//[5];//VARCHAR2(8) 成功 0
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
public string CONS_NO;//[17];//VARCHAR2(16) 用户编号
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct FeedBackBXCardReturn
{
public bool bOK;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string RETURN_CODE;//[5];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string RETURN_MSG;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string REMARK1;//[129];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string REMARK2;//[129];
}
[DllImport("PowerDll.dll", EntryPoint = "WEB_SetPowerPZ",CharSet = CharSet.Ansi)]
public static extern void WEB_SetPowerPZ(string sQDNO0, string sKey0, string sSYSNO0);
[DllImport("PowerDll.dll", EntryPoint = "WEB_SetPowerPZ2")]
public static extern void WEB_SetPowerPZ2(string sDLIP, string sDLPort, string sQDNO0, string sKey0, string sSYSNO0);
[DllImport("PowerDll.dll", EntryPoint = "WEB_AskQF")]
public static extern bool WEB_AskQF(string sWDBM, string sCZNO, string sIndex, string sKHNO, ref AskQFReturn m_AskQFReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_PutInQF")]
public static extern bool WEB_PutInQF(string sWDBM, string sCZNO, string sIndex, string BATCH_NO, ref PutInQF m_PutInQF, ref PutInQFReturn m_PutInQFReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_RestorePutInQF")]
public static extern bool WEB_RestorePutInQF(string sWDBM, string sCZNO, string sIndex, ref RestorePutInQF m_RetorePutInQF, ref RestorePutInQFReturn m_RestorePutInQFReturn);
//卡表
[DllImport("PowerDll.dll", EntryPoint = "WEB_AskPowerCard")]
public static extern bool WEB_AskPowerCard(string sWDBM, string sCZNO, string sIndex, ref AskPowerCard m_AskPowerCard, ref AskPowerCardReturn m_AskPowerCardReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_BuyPowerCard")]
public static extern bool WEB_BuyPowerCard(string sWDBM, string sCZNO, string sIndex, ref BuyPowerCard m_BuyPowerCard, ref BuyPowerCardReturn m_BuyPowerCardReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_RestoreBuyPowerCard")]
public static extern bool WEB_RestoreBuyPowerCard(string sWDBM, string sCZNO, string sIndex, ref RestoreBuyPowerCard m_RestoreBuyPowerCard, ref RestoreBuyPowerCardReturn m_RestoreBuyPowerCardReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_BXCard")]
public static extern bool WEB_BXCard(string sWDBM, string sCZNO, string sIndex, ref BXCard m_BXCard, ref BXCardReturn m_BXCardReturn);
[DllImport("PowerDll.dll", EntryPoint = "WEB_AskTicket")]
public static extern bool WEB_AskTicket(string sWDBM, string sCZNO, string sIndex, ref AskTicket m_AskTicket, ref AskTicketReturn m_AskTicketReturn);
//对账户
[DllImport("PowerDll.dll", EntryPoint = "WEB_PowerDZ")]
public static extern bool WEB_PowerDZ(string sWDBM, string sCZNO, string sIndex, ref PowerDZ m_PowerDZ, ref PowerDZReturn m_PowerDZReturn);
//回馈补写卡
[DllImport("PowerDll.dll", EntryPoint = "WEB_FeedBackBXCard")]
public static extern bool WEB_FeedBackBXCard(string sWDBM, string sCZNO, string sIndex, ref FeedBackBXCard m_FeedBackBXCard, ref FeedBackBXCardReturn m_FeedBackBXCardReturn);
//电力功能结束
C++
extern CString sGlobalQDNO,sGlobalKey,sGlobalSYSNO;
extern BOOL WINAPI WEB_AskQF(char *sWDBM,char *sCZNO,char *sIndex,char *sKHNO,struct AskQFReturn *pAskQFReturn)
{
return PowerNetLayer::APP_AskQF(sWDBM,sCZNO,sIndex,sKHNO,pAskQFReturn);
}
extern BOOL WINAPI WEB_PutInQF(char *sWDBM,char *sCZNO,char *sIndex,char * BATCH_NO,struct PutInQF *pPutInQF,struct PutInQFReturn *pPutInQFReturn)
{
return PowerNetLayer::APP_PutInQF(sWDBM,sCZNO,sIndex,BATCH_NO,pPutInQF,pPutInQFReturn);
}
extern BOOL WINAPI WEB_RestorePutInQF(char *sWDBM,char *sCZNO,char *sIndex, RestorePutInQF *pRetorePutInQF, RestorePutInQFReturn *pRestorePutInQFReturn)
{
return PowerNetLayer::APP_RestorePutInQF(sWDBM,sCZNO, sIndex, pRetorePutInQF, pRestorePutInQFReturn);
}
//卡表
extern BOOL WINAPI WEB_AskPowerCard(char *sWDBM,char *sCZNO,char *sIndex,AskPowerCard *pAskPowerCard,AskPowerCardReturn *pAskPowerCardReturn)
{
return PowerNetLayer::APP_AskPowerCard(sWDBM,sCZNO,sIndex,pAskPowerCard,pAskPowerCardReturn);
}
extern BOOL WINAPI WEB_BuyPowerCard(char *sWDBM,char *sCZNO,char *sIndex,BuyPowerCard *pBuyPowerCard,BuyPowerCardReturn *pBuyPowerCardReturn)
{
return PowerNetLayer::APP_BuyPowerCard(sWDBM,sCZNO,sIndex,pBuyPowerCard,pBuyPowerCardReturn);
}
extern BOOL WINAPI WEB_RestoreBuyPowerCard(char *sWDBM,char *sCZNO,char *sIndex,RestoreBuyPowerCard *pRestoreBuyPowerCard,RestoreBuyPowerCardReturn *pRestoreBuyPowerCardReturn)
{
return PowerNetLayer::APP_RestoreBuyPowerCard(sWDBM,sCZNO,sIndex,pRestoreBuyPowerCard,pRestoreBuyPowerCardReturn);
}
extern BOOL WINAPI WEB_BXCard(char *sWDBM,char *sCZNO,char *sIndex,BXCard *pBXCard,BXCardReturn *pBXCardReturn)
{
return PowerNetLayer::APP_BXCard( sWDBM,sCZNO,sIndex,pBXCard,pBXCardReturn);
}
extern BOOL WINAPI WEB_AskTicket(char *sWDBM,char *sCZNO,char *sIndex,AskTicket *pAskTicket,AskTicketReturn *pAskTicketReturn)
{
return PowerNetLayer::APP_AskTicket( sWDBM,sCZNO,sIndex,pAskTicket,pAskTicketReturn);
}
//对账户
extern BOOL WINAPI WEB_PowerDZ(char *sWDBM,char *sCZNO,char *sIndex,PowerDZ *pPowerDZ,PowerDZReturn *pPowerDZReturn)
{
return PowerNetLayer::APP_PowerDZ(sWDBM,sCZNO, sIndex,pPowerDZ,pPowerDZReturn);
}
extern void WINAPI WEB_SetPowerPZ(char *sQDNO0,char *sKey0,char *sSYSNO0)
{
sGlobalQDNO.Format("%s",sQDNO0);
sGlobalKey.Format("%s",sKey0);
sGlobalSYSNO.Format("%s",sSYSNO0);
}
extern void WINAPI WEB_SetPowerPZ2(char *sDLIP,char *sPort,char *sQDNO0,char *sKey0,char *sSYSNO0)
{
PowerNetLayer::nPort=atoi(sPort);
sprintf(PowerNetLayer::sIP,"%s",sDLIP);
sGlobalQDNO.Format("%s",sQDNO0);
sGlobalKey.Format("%s",sKey0);
sGlobalSYSNO.Format("%s",sSYSNO0);
CString sMsg;
sMsg.Format("设置IP:%s,端口:%d",PowerNetLayer::sIP,PowerNetLayer::nPort);
XSocketBase::WriteLog(sMsg);
}
C#双面打印解决方法(打印word\excel\图片
直接设置打印机单双面的代码,非常管用。
using System.Runtime.InteropServices;
using System;
namespace MyDuplexSettings
{
class DuplexSettings
{
#region Win32 API Declaration
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)]
string pDeviceNameg, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, ref Int32 dwNeeded);
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, ref PRINTER_DEFAULTS pDefault);
[DllImport("winspool.Drv", EntryPoint = "SetPrinterA", ExactSpelling = true, SetLastError = true)]
public static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public IntPtr pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_9
{
public IntPtr pDevMode;
// Pointer to SECURITY_DESCRIPTOR
public int pSecurityDescriptor;
}
public const short CCDEVICENAME = 32;
public const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
public const Int64 DM_DUPLEX = 0x1000L;
public const Int64 DM_ORIENTATION = 0x1L;
public const Int64 DM_SCALE = 0x10L;
public const Int64 DMORIENT_PORTRAIT = 0x1L;
public const Int64 DMORIENT_LANDSCAPE = 0x2L;
public const Int32 DM_MODIFY = 8;
public const Int32 DM_COPY = 2;
public const Int32 DM_IN_BUFFER = 8;
public const Int32 DM_OUT_BUFFER = 2;
public const Int32 PRINTER_ACCESS_ADMINISTER = 0x4;
public const Int32 PRINTER_ACCESS_USE = 0x8;
public const Int32 STANDARD_RIGHTS_REQUIRED = 0xf0000;
public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
//added this
public const int CCHDEVICENAME = 32;
//added this
public const int CCHFORMNAME = 32;
#endregion
#region Public Methods
/// <summary>
/// Method Name : GetPrinterDuplex
/// Programmatically get the Duplex flag for the specified printer
/// driver's default properties.
/// </summary>
/// <param name="sPrinterName"> The name of the printer to be used. </param>
/// <param name="errorMessage"> this will contain error messsage if any. </param>
/// <returns>
/// nDuplexSetting - One of the following standard settings:
/// 0 = Error
/// 1 = None (Simplex)
/// 2 = Duplex on long edge (book)
/// 3 = Duplex on short edge (legal)
/// </returns>
/// <remarks>
/// </remarks>
public short GetPrinterDuplex(string sPrinterName, out string errorMessage)
{
errorMessage = string.Empty;
short functionReturnValue = 0;
IntPtr hPrinter = default(IntPtr);
PRINTER_DEFAULTS pd = default(PRINTER_DEFAULTS);
DEVMODE dm = new DEVMODE();
int nRet = 0;
pd.DesiredAccess = PRINTER_ACCESS_USE;
nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
if ((nRet == 0) | (hPrinter.ToInt32() == 0)) {
if (GetLastError() == 5) {
errorMessage = "Access denied -- See the article for more info.";
} else {
errorMessage = "Cannot open the printer specified " + "(make sure the printer name is correct).";
}
return functionReturnValue;
}
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0);
if ((nRet < 0)) {
errorMessage = "Cannot get the size of the DEVMODE structure.";
goto cleanup;
}
IntPtr iparg = Marshal.AllocCoTaskMem(nRet + 100);
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
if ((nRet < 0)) {
errorMessage = "Cannot get the DEVMODE structure.";
goto cleanup;
}
dm = (DEVMODE)Marshal.PtrToStructure(iparg, dm.GetType());
if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX)) {
errorMessage = "You cannot modify the duplex flag for this printer " + "because it does not support duplex or the driver " + "does not support setting it from the Windows API.";
goto cleanup;
}
functionReturnValue = dm.dmDuplex;
cleanup:
if ((hPrinter.ToInt32() != 0))
ClosePrinter(hPrinter);
return functionReturnValue;
}
/// <summary>
/// Method Name : SetPrinterDuplex
/// Programmatically set the Duplex flag for the specified printer driver's default properties.
/// </summary>
/// <param name="sPrinterName"> sPrinterName - The name of the printer to be used. </param>
/// <param name="nDuplexSetting">
/// nDuplexSetting - One of the following standard settings:
/// 1 = None
/// 2 = Duplex on long edge (book)
/// 3 = Duplex on short edge (legal)
/// </param>
/// <param name="errorMessage"> this will contain error messsage if any. </param>
/// <returns>
/// Returns: True on success, False on error.
/// </returns>
/// <remarks>
///
/// </remarks>
public bool SetPrinterDuplex(string sPrinterName, int nDuplexSetting, out string errorMessage)
{
errorMessage = string.Empty;
bool functionReturnValue = false;
IntPtr hPrinter = default(IntPtr);
PRINTER_DEFAULTS pd = default(PRINTER_DEFAULTS);
PRINTER_INFO_9 pinfo = new PRINTER_INFO_9();
DEVMODE dm = new DEVMODE();
IntPtr ptrPrinterInfo = default(IntPtr);
int nBytesNeeded = 0;
int nRet = 0;
Int32 nJunk = default(Int32);
if ((nDuplexSetting < 1) | (nDuplexSetting > 3)) {
errorMessage = "Error: dwDuplexSetting is incorrect.";
return functionReturnValue;
}
pd.DesiredAccess = PRINTER_ACCESS_USE;
nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
if ((nRet == 0) | (hPrinter.ToInt32() == 0)) {
if (GetLastError() == 5) {
errorMessage = "Access denied -- See the article for more info." ;
} else {
errorMessage = "Cannot open the printer specified " + "(make sure the printer name is correct).";
}
return functionReturnValue;
}
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0);
if ((nRet < 0)) {
errorMessage = "Cannot get the size of the DEVMODE structure.";
goto cleanup;
}
IntPtr iparg = Marshal.AllocCoTaskMem(nRet + 100);
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
if ((nRet < 0)) {
errorMessage = "Cannot get the DEVMODE structure.";
goto cleanup;
}
dm = (DEVMODE)Marshal.PtrToStructure(iparg, dm.GetType());
if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX)) {
errorMessage = "You cannot modify the duplex flag for this printer " + "because it does not support duplex or the driver " + "does not support setting it from the Windows API.";
goto cleanup;
}
dm.dmDuplex = (short) nDuplexSetting;
Marshal.StructureToPtr(dm, iparg, true);
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pinfo.pDevMode, pinfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if ((nRet < 0)) {
errorMessage = "Unable to set duplex setting to this printer.";
goto cleanup;
}
GetPrinter(hPrinter, 9, IntPtr.Zero, 0, ref nBytesNeeded);
if ((nBytesNeeded == 0)) {
errorMessage = "GetPrinter failed.";
goto cleanup;
}
ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded + 100);
nRet = GetPrinter(hPrinter, 9, ptrPrinterInfo, nBytesNeeded, ref nJunk)?1:0;
if ((nRet == 0)) {
errorMessage = "Unable to get shared printer settings.";
goto cleanup;
}
pinfo = (PRINTER_INFO_9)Marshal.PtrToStructure(ptrPrinterInfo, pinfo.GetType());
pinfo.pDevMode = iparg;
pinfo.pSecurityDescriptor = 0;
Marshal.StructureToPtr(pinfo, ptrPrinterInfo, true);
nRet = SetPrinter(hPrinter, 9, ptrPrinterInfo, 0)?1:0;
if ((nRet == 0)) {
errorMessage = "Unable to set shared printer settings.";
}
functionReturnValue = Convert.ToBoolean(nRet);
cleanup:
if ((hPrinter.ToInt32() != 0))
ClosePrinter(hPrinter);
return functionReturnValue;
}
#endregion
}
}
使用方法,以word为例:
public static void PrintWord(string FileName, PrintDocument pd)
{
//0 check if there are any winword process exist
//if is,kill it
Process[] wordProcess = Process.GetProcessesByName("WINWORD");
for (int i = 0; i < wordProcess.Length; i++)
{
wordProcess.Kill();
}
object missing = System.Reflection.Missing.Value;
object objFileName = FileName;
object objPrintName = pd.PrinterSettings.PrinterName;
WORD.Application objApp = new WORD.Application();
WORD.Document objDoc = null;
try
{
objDoc = FrameWork.WordTool.OpenWord(objApp, FileName);
objDoc.Activate();
object copies = "1";
object pages = "";
object range = WORD.WdPrintOutRange.wdPrintAllDocument;
object items = WORD.WdPrintOutItem.wdPrintDocumentContent;
object pageType = WORD.WdPrintOutPages.wdPrintAllPages;
object oTrue = true;
object oFalse = false;
objApp.Options.PrintOddPagesInAscendingOrder = true;
objApp.Options.PrintEvenPagesInAscendingOrder = true;
objDoc.PrintOut(
ref oTrue, ref oFalse, ref range, ref missing, ref missing, ref missing,
ref items, ref copies, ref pages, ref pageType, ref oFalse, ref oTrue,
ref missing, ref oFalse, ref missing, ref missing, ref missing, ref missing);
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (objDoc != null)
{
Marshal.ReleaseComObject(objDoc);
Marshal.FinalReleaseComObject(objDoc);
objDoc = null;
}
if (objApp != null)
{
objApp.Quit(ref missing, ref missing, ref missing);
Marshal.ReleaseComObject(objApp);
Marshal.FinalReleaseComObject(objApp);
objApp = null;
}
}
}
使用方法,以excel为例,我这有两种表格,把打印页数固定了打印:
public static void PrintExcel(string excelFileName, PrintDocument pd, int iFlag)
{
//0 check if there are any winword process exist
//if is,kill it
Process[] wordProcess = Process.GetProcessesByName("EXCEL");
for (int i = 0; i < wordProcess.Length; i++)
{
wordProcess.Kill();
}
object Missing = System.Reflection.Missing.Value;
object objExcel = null;
object objWorkbooks = null;
try
{
objExcel = ExcelTool.OpenExcel(excelFileName);
if (iFlag == 1)
{
objWorkbooks = ExcelTool.GetWorkSheets(objExcel);
object[] parameters = null;
try
{
parameters = new object[8];
parameters[0] = 1;
parameters[1] = 4;
parameters[2] = 1;
parameters[3] = Missing;
parameters[4] = pd.PrinterSettings.PrinterName;
parameters[5] = Missing;
parameters[6] = true;
parameters[7] = Missing;
objWorkbooks.GetType().InvokeMember("PrintOut", System.Reflection.BindingFlags.InvokeMethod, null, objWorkbooks, parameters);
}
catch (Exception ex)
{
throw ex;
}
}
else
{
objWorkbooks = ExcelTool.GetWorkSheets(objExcel);
object[] parameters = null;
try
{
parameters = new object[8];
parameters[0] = 5;
parameters[1] = 5;
parameters[2] = 1;
parameters[3] = Missing;
parameters[4] = pd.PrinterSettings.PrinterName;
parameters[5] = Missing;
parameters[6] = true;
parameters[7] = Missing;
objWorkbooks.GetType().InvokeMember("PrintOut", System.Reflection.BindingFlags.InvokeMethod, null, objWorkbooks, parameters);
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (objWorkbooks != null)
{
ExcelTool.ReleaseComObj(objWorkbooks);
}
if (objExcel != null)
{
ExcelTool.ReleaseComObj(objExcel);
}
System.GC.Collect();
}
}
最后再说说图片打印A4纸的设置,这里省略其它代码,如果纠结这问题的人一下就看出来问题出哪里了。
如果要适应纸张尺寸的话:
pd.PrintPage += (_, e) =>
{
var img = System.Drawing.Image.FromFile(FileName);
e.Graphics.DrawImage(img, 20, 20, e.PageSettings.PrintableArea.Width, e.PageSettings.PrintableArea.Height);
if (i == FileName.Length - 1)
{
e.HasMorePages = false;
}
else
{
e.HasMorePages = true;
}
i++;
};
如果是固定大小的话:
pd.PrintPage += (_, e) =>
{
var img = System.Drawing.Image.FromFile(FileName);
int iWidth = 520;
double hFactor = iWidth / (double)img.Width;
int iHeight = Convert.ToInt32(img.Height * hFactor);
Rectangle Rect = new Rectangle(170, 330, iWidth, iHeight);
e.Graphics.DrawImage(img, Rect);
if (i == FileName.Length - 1)
{
e.HasMorePages = false;
}
else
{
e.HasMorePages = true;
}
i++;
};
数据在渲染前提供给引擎,不要在页面生成新的对象,不要修改页面模型数据,以免出现不可预的错误
赋值标签
语法:$set(名称=值)
var templateContent = "${set(id=10)}${id}";
var template = Engine.CreateTemplate(templateContent);
var result = template.Render();
点击项目 - 管理NUGET程序包,点击浏览,输入jntemplate,安装好包JinianNet.JNTemplate.
var template = Engine.CreateTemplate("Hello $name!");
template.Set("name", "World");
template.Render(Console.Out);
Engine.CreateTemplate("Hello $name!"); 表示从文本"Hello $name!" 创建一个模板对象,如果是从一个文件创建模板可以使用 Engine.LoadTemplate("文件路径")
特别注意当数据为Hashtable型时,里面不能包含对象,只能单纯数字,字符串等
error:
oneData m_oneData=new oneData();
Hashtable m_HH=new Hashtable();
m_HH["A"]=m_oneData;
m_HH["B"=123;
m_HH["C"]="hello world";
template.Set("name","World"); 将一个名称为name的变量给递给模板。
template.Render(Console.Out); 解析呈现模板内容。
在这里,直接将模板解析结果呈现到了控制台,如果需要输出到文本,可以直接使用
string result = template.Render();
如果想保存到文件,可以参考下面的写法
using (var sw = File.CreateText(@"c:\wwwroot\index.html"))
{
template.Render(sw);
}
.net 开源模板引擎jntemplate 教程:基础篇之语法
一、基本概念
标签通常使用${开头,并且以}结尾,绝大部分标签可以省略大括号进行简写,如${model.UserName} 可以简写为 $model.UserName
注意:标签的符号是可以自定义的,比如你可以自定义为{{model.UserName}} 或者@{model.UserName},本文为了方便讲解,仅以默认配置为准。
二、变量
用法:用于在模板中输出一个变量,该变量可以是任何对象。如:${var},可以简写为$var,其中var 为变量名,变量名只能是字母,下划线与数字的组合,且必须以字母开头。
例:
var template = Engine.CreateTemplate("<h1>$title</h1>!");
template.Set("title", "jntemplate");
template.Render(Console.Out);
三、属性与字段
用法: 用于访问对象属性或者字段,用法与c#类似,字段与属性必须是公开的(public),v2.0.0 中暂时不支持匿名对象的访问。如:${model.Name},可以简写为$model.Name.
例一:
var template = Engine.CreateTemplate("<h1>$model.Title</h1>!");
template.Set("model", new Site{ Title="jntemplate" });
template.Render(Console.Out);
如果访问静态属性或字段,需要通过template.SetStaticType(...)来指定静态对象类型。
例二:
var templateContent = "${DateTime.Now}";
var template = Engine.CreateTemplate(templateContent);
template.SetStaticType("DateTime", typeof(DateTime));
template.Render(Console.Out);
四、索引
用法:用于访问数组或者IList<T>及其它支持索引的对象,用法与c#类似,如${arr[1]}
例:
var template = Engine.CreateTemplate("${arr[0]}");
template.SetStaticType("arr", new int[]{ 1,2,3});
template.Render(Console.Out);
五、函数方法
用法:用于调用对象实例方法,静态方法,或者委托。如:${func(p1,p2....) },可以简写为$func(p1,p2....)。
注意:方法必须是公开的(public),如果是私有的(private)则无法访问。
例一(实例方法):
Class1类
public class Class1
{
public int Add(int a,int b)
{
return a+b;
}
}
模板代码:
var template = Engine.CreateTemplate("$obj.Add(1,2)");
template.Set("obj", new Class1());
template.Render(Console.Out);
例二(静态方法):
var templateContent = "${string.Concat(\"str1\",\"str2\")}";
var template = Engine.CreateTemplate(templateContent);
template.SetStaticType("string", typeof(string));
template.Render(Console.Out);
例三(委托方法):
var template = Engine.CreateTemplate("$add(8,-2)");
template.Set<Func<int, int, int>>("add", (x, y) =>
{
return x + y;
});
template.Render(Console.Out);
六、逻辑判断(IF)
用法:用于处理代码逻辑,等同于c#里面的if与else if,支持以下逻辑运算符:大于(>),小于(<),大于等于(>=),小于等于(<=),等于(==),不等于(!=),或者(||), 并且(&&)。
例一:
模板:demo.html
<span>
$if(id>0)
编号大于零
$elif(id==0)
编号等于零
$else
编号小于零
$end
</span>
后台代码:
var template = Engine.LoadTemplate(@"c:\demo.html");
template.Set("id",15);
template.Render(Console.Out);
注意:else if 可以写作$elseif 也可以写作 $elif。标签必须以$end结束
七、列表迭代(Foreach)
用法:用来遍历输出一个列表,等同于c#中foreach,目标可以是数组或者实现了IEnumerable 接口的任意对象.
例一:
模板:demo.html
$foreach(model in list)
<ul>
<li><a href="${model.Url}">${model.Title}</a></li></li>
</ul>
$end
var template = Engine.LoadTemplate(@"c:\demo.html");
template.Set("list",new NewInfo[]{ ... });
template.Render(Console.Out);
$foreach(model in list) 也可以写作 $for(model in list) ,必须使用$end 结束标签。
八、模板引用
用法:用于引用某一个公共模板,有二种写法$load("路径")与$inclub("路径"):
load 引用并解析模板
inclub:引用模板(不解析),适用于不需要解析的文件,比如JS,CSS等
例:
$load("public/header.html")
<div>这是内容</div>
九、总结
本文介绍了jntemplate常用的模板语法,包括变量,属性,方法,逻辑判断,迭代与模板引用这几大块,只要灵活组合使用,完全可以满足日常开发了。
部分不怎么常用的语法大家可以自行可以参考官方文档。
自己的测试代码
封装
class JNTemplateEngine: IDisposable
{
JinianNet.JNTemplate.ITemplate ITemplate = null;
HttpContext ctx = null;
PageEngine m_PageEngine = null;
public JNTemplateEngine(HttpContext ctx, string m_ModePath, string src, Object m_Model, bool bFile = true)
{
this.ctx = ctx;
if (bFile)
ITemplate = Engine.LoadTemplate(src);
else
{
ITemplate = Engine.CreateTemplate(src);
}
ITemplate.Set("model", m_Model);
m_PageEngine = new PageEngine(ctx, m_ModePath);
ITemplate.Set("engine",m_PageEngine);
ITemplate.SetStaticType("JsonHelper", typeof(JsonHelper));
}
public void Dispose()
{
if(ITemplate!=null)
{
ITemplate=null;
}
if(m_PageEngine!=null)
{
m_PageEngine = null;
}
}
public bool Render(out string sText)
{
sText = "";
try
{
sText = ITemplate.Render();
return true;
}
catch (Exception e)
{
sText = e.ToString();
return false;
}
}
}
public class PageEngine : BaseJsonMode
{
HttpContext ctx = null;
string m_ModePath,ModeUrl="";
public PageEngine(HttpContext ctx, string m_ModePath)
{
this.ctx = ctx;
this.m_ModePath = m_ModePath;
string ViewPath = "~\\" + m_ModePath + "\\View\\";
ViewPath = ViewPath.Replace("\\", "/");
int nPos = ViewPath.IndexOf("View/");
string MainViewPath = "";
if (nPos != -1)
{
MainViewPath = ViewPath.Substring(1, nPos + 4);
}
ModeUrl = GetResourceUrl() + MainViewPath;
}
public SessionLink GetSessionLink()
{
return BaseJsonMode.GetSessionLink(ctx);
//SessionLink m_SessionLink = new SessionLink();
//m_SessionLink.username = "xuneng";
//return m_SessionLink;
}
public bool HavePower(string FullClassName, string FunctionName)
{
return BaseJsonMode.HavePower(ctx, FullClassName, FunctionName, true).bOK;
//return true;
}
public bool SaveCookie(string name, string value)
{
return BaseJsonMode.SaveCookie(ctx, name, value);
//return false;
}
public string ReadCookie(string name)
{
return BaseJsonMode.ReadCookie(ctx, name);
//return "";
}
public void ClearCookie(string name)
{
BaseJsonMode.ClearCookie(ctx, name);
//return;
}
public ReturnJson CallJsonModeFunction(string ClassFullName, string FunctionName, Object m_InParame)
{
ReturnJson m_ReturnJson = new ReturnJson();
//return m_ReturnJson;
if (BaseJsonMode.CallJsonModeFunction(ctx, ClassFullName, FunctionName, m_InParame, true, out m_ReturnJson.m_ReturnOBJ, out m_ReturnJson.sMsg))
{
m_ReturnJson.bOK = true;
return m_ReturnJson;
}
else
{
m_ReturnJson.bOK = false;
return m_ReturnJson;
}
}
public string RenderModeHTML(string classfullname, string functionname, object m_InParame)
{
//return "";
ReturnJson m_ReturnJson = CallJsonModeFunction(classfullname, functionname, m_InParame);
if (m_ReturnJson.bOK)
{
return m_ReturnJson.m_ReturnOBJ.ToString();
}
else
{
return m_ReturnJson.sMsg;
}
}
public string GetResourceUrl()
{
return BaseJsonMode.GetResourceUrl(ctx);
}
public OneUpFileWEB GetUpFileURL()
{
return BaseJsonMode.GetUpFileURL(ctx);
}
public bool HaveCrossPower(string sClassFullName, string sFunctionName, string sys_companys_nodeuuid)
{
return BaseJsonMode.HaveCrossPower(ctx, sClassFullName, sFunctionName, sys_companys_nodeuuid, true).bOK;
}
protected List<string> GetUrlDotListString()
{
if (ctx.Items.Contains("headDot"))
{
return (List<string>)ctx.Items["headDot"];
}
string[] sDotArray = ctx.Request.FilePath.Split('/');
int nCnt = sDotArray.Length;
List<string> m_List = new List<string>();
if (nCnt >= 3)
{
if (nCnt == 3)
{
ctx.Items["headDot"] = m_List;
return m_List;
}
else
{
//string[] m_ReturnDotArray = new string[nCnt - 3];
for (int i = 1; i < 1 + nCnt - 3; i++)
{
m_List.Add(sDotArray[i]);
}
ctx.Items["headDot"] = m_List;
return m_List;
}
}
else
{
ctx.Items["headDot"] = m_List;
return m_List;
}
}
public string GetUrlHead()
{
List<string> m_HeadList = GetUrlDotListString(ctx);
if (m_HeadList.Count > 0)
{
string str = "";
for (int i = 0; i < m_HeadList.Count; i++)
{
str += "/" + m_HeadList[i];
}
str += "/";
return str;
}
else
{
return "/";
}
}
public string GetModeUrl()
{
return ModeUrl;
}
public bool IsPCClient()
{
return BaseJsonMode.IsPCClient(ctx);
}
public bool isHTTPS()
{
return ctx.Request.IsSecureConnection;
}
}
使用
public class oneData
{
public Hashtable m_HH;
public string A;
public int B;
public oneData m_oneData;
public List<oneRow> m_RowArray;
public List<Hashtable> m_HHList;
}
public class oneRow
{
public int pos;
}
oneData m_oneData = new oneData();
m_oneData.m_HH = new Hashtable();
m_oneData.A = "1";
m_oneData.B = 2;
m_oneData.m_HH["A"] = type;
m_oneData.m_oneData = new oneData();
m_oneData.m_oneData.m_HH = new Hashtable();
m_oneData.m_oneData.A = "11";
m_oneData.m_oneData.B = 22;
m_oneData.m_oneData.m_HH["A"] = "下级测试数据";
oneData m_oneData0 = new oneData();
m_oneData0.A = "c1";
m_oneData.m_HH["m_oneData"] = m_oneData0;//错误Hashtable内只能包含基本数据类型如int string float double 不能包含对象否则模板访问失败
int i;
List<Hashtable> m_HHList = new List<Hashtable>();
for (i = 0; i < 10; i++)
{
Hashtable m_oneHH = new Hashtable();
m_oneHH["pos"] = i;
m_HHList.Add(m_oneHH);
}
m_oneData.m_oneData.m_HHList = m_HHList;
List<oneRow> m_RowArray = new List<oneRow>();
for (i = 0; i < 10; i++)
{
oneRow m_oneRow = new oneRow();
m_oneRow.pos = i;
m_RowArray.Add(m_oneRow);
}
m_oneData.m_oneData.m_HH["array"] = m_RowArray.ToArray();
m_oneData.m_oneData.m_RowArray = m_RowArray;
string output="";
using (JNTemplateEngine m_JNTemplateEngine = new JNTemplateEngine(m_ctx, m_ModePath, FName, m_oneData, true))
{
m_JNTemplateEngine.Render(out output);
}
FName的内容:
m_oneData.A:${model.A},m_oneData.B:${model.B},m_oneData.m_HH["A"]:${model.m_HH["A"]},m_oneData.m_oneData.A:${model.m_oneData.A},m_oneData.m_oneData.B:${model.m_oneData.B},m_oneData.m_oneData.m_HH["A"]:${model.m_oneData.m_HH["A"]},m_SessionLink.username:${engine.GetSessionLink().username}
权限判断:CoreSYS.SYS/AddCompany:${if(engine.HavePower("CoreSYS.SYS","AddCompany"))}有权限执行${else}无权限执行${end}
对象列表数据:${foreach(one in model.m_oneData.m_RowArray)}序号-${one.pos} ${end}<br />
Hashtable的List列表数据:${foreach(one in model.m_oneData.m_HHList)}序号-${one["pos"]} ${end}</br>
Hashtable中对象${model.m_HH["m_oneData"]}</br>
引号内</br>
Hashtable的List列表数据:"${foreach(one in model.m_oneData.m_HHList)}序号-${one["pos"]} ${end}"</br>
模板页内变量使用<br />
${set(a=123)}<br />
输出:${a}
<br />
<ul>
定义ii变量
${set(ii=0)}
${for(ii=1;ii<4;ii++)}
<li>${ii}</li>
${end}
</ul>
C#嵌入x86汇编——一个GPIO接口的实现
C#嵌入x86汇编——一个GPIO接口的实现
买的工控机带有GPIO接口,可用于直接控制继电器
常见有四种办法,分别是四种语言实现,一是直接写ASM,不过要公开给C#做的应用程序调用,很不容易,另外三种是C/C++/Delphi嵌入汇编,倒是问题不大。
接口实在是小,不想大动干戈,所以想了别的办法。
第五种,用C++/CLI,这也是一个不错的主意。但是我甚至想省掉这个接口DLL,于是有了第六种办法:C#嵌入x86汇编。
C#是没办法像C/C++/Delphi那样直接嵌入x86汇编的,所以需要做点手脚。
在汇编里面,我们为了修改一个软件经常找一块空白区域来写汇编代码,然后Jmp过去执行。(不明白这一句话的可以跳过,或者去看雪论坛)
但是显然要在C#代码里面这么做很不现实,即使用C/C++编译得到obj,C#也没办法链接这个obj。(这个涉及编译的也可以跳过)
回头一想(其实不是现在想,07年就做过C#嵌入汇编),其实C#也跑在x86上,IL指令最终还是要编译成x86汇编指令的,我们应该可以这些写汇编指令,所需要的只是一块空间而已。
我们可以申请一块非托管空间嘛,于是有:
// 分配内存
var ptr = Marshal.AllocHGlobal(code.Length);
有了空间,我们就可以把二进制的汇编指令给写进去啦:
Marshal.Copy(code, 0, ptr, code.Length);
然后呢?.Net提供一个途径,让我们可以把一个内存指针转为一个委托(一直都说.Net的委托其实就是C/C++的函数指针哈):
return
(T)(Object)Marshal.GetDelegateForFunctionPointer(ptr,
typeof
(T));
那么,剩下的问题,就是如何把汇编转为二进制了!
这个我们是不能像C/C++/Delphi那样直接写汇编指令的,所以得走点弯路。
我的做法是用OD随便打开一个程序,在上面直接写汇编代码,然后把汇编的十六进制复制出来,放到C#代码中。
剩下的就不多说了,直接上代码吧!
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
namespace ConsoleApplication19
{
class GPIO
{
#region 属性
private Int32 _Offset;
/// <summary>选择位移</summary>
public Int32 Offset { get { return _Offset; } set { _Offset = value; } }
private Int32 _Bit;
/// <summary>选择位</summary>
public Int32 Bit { get { return _Bit; } set { _Bit = value; } }
#endregion
#region 构造
private GPIO(Int32 offset, Int32 bit)
{
Offset = offset;
Bit = bit;
}
private GPIO(Int32 gpio)
{
Offset = gpio / 16;
Bit = gpio % 16;
}
#endregion
#region 预定义针脚
public static GPIO Pin2 = new GPIO(0, 6);
public static GPIO Pin3 = new GPIO(0, 7);
public static GPIO Pin4 = new GPIO(2, 1);
public static GPIO Pin5 = new GPIO(2, 4);
public static GPIO Pin6 = new GPIO(1, 0);
public static GPIO Pin7 = new GPIO(1, 4);
public static GPIO Pin8 = new GPIO(3, 3);
public static GPIO Pin9 = new GPIO(3, 4);
public static GPIO IO6 = new GPIO(6);
public static GPIO IO7 = new GPIO(7);
public static GPIO IO17 = new GPIO(17);
public static GPIO IO20 = new GPIO(20);
public static GPIO IO8 = new GPIO(8);
public static GPIO IO12 = new GPIO(12);
public static GPIO IO27 = new GPIO(27);
public static GPIO IO28 = new GPIO(28);
#endregion
#region 业务
/// <summary>是否启用</summary>
public Boolean Enable { get { return Read(Offset, Bit); } set { WriteBit(Offset, Bit, value); } }
/// <summary>是否输出</summary>
public Boolean Output { get { return Read(Offset + 4, Bit); } set { WriteBit(Offset + 4, Bit, value); } }
/// <summary>是否设置数据位</summary>
public Boolean Data { get { return Read(Offset + 12, Bit); } set { WriteBit(Offset + 12, Bit, value); } }
#endregion
#region 读取端口
const Int16 BASEADDRESS = 0x500;
Boolean Read(Int32 offset, Int32 bit)
{
var d = ReadHandler((Int16)(BASEADDRESS + offset));
var c = (Byte)~(1 << bit);
d &= c;
return d == c;
}
private static ReadFunc _ReadHandler;
/// <summary>属性说明</summary>
public static ReadFunc ReadHandler { get { return _ReadHandler ?? (_ReadHandler = GetReadHandler()); } }
//static IntPtr ptr;
static ReadFunc GetReadHandler()
{
// 汇编指令
var code = new Byte[] {
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0xEC, //in al, dx
};
return (ReadFunc)InjectASM<ReadFunc>(code);
}
public delegate Byte ReadFunc(Int16 address);
#endregion
#region 写入端口
void Write(Int32 offset, Int32 value)
{
WriteHandler((Int16)(BASEADDRESS + offset), (Byte)value);
}
private static WriteFunc _WriteHandler;
/// <summary>属性说明</summary>
public static WriteFunc WriteHandler { get { return _WriteHandler ?? (_WriteHandler = GetWriteHandler()); } }
static WriteFunc GetWriteHandler()
{
// 汇编指令
var code = new Byte[] {
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xEE //out dx, al
};
return InjectASM<WriteFunc>(code);
}
public delegate void WriteFunc(Int16 address, Byte bit);
#endregion
#region 写入端口位
void WriteBit(Int32 offset, Int32 bit, Boolean value)
{
if (value)
SetBitHandler((Int16)(BASEADDRESS + offset), (Byte)bit);
else
ClearBitHandler((Int16)(BASEADDRESS + offset), (Byte)bit);
}
private static WriteBitFunc _SetBitHandler;
/// <summary>设置位</summary>
public static WriteBitFunc SetBitHandler { get { return _SetBitHandler ?? (_SetBitHandler = GetSetBitHandler()); } }
private static WriteBitFunc _ClearBitHandler;
/// <summary>清除位</summary>
public static WriteBitFunc ClearBitHandler { get { return _ClearBitHandler ?? (_ClearBitHandler = GetClearBitHandler()); } }
static WriteBitFunc GetSetBitHandler()
{
// 汇编指令
var code = new Byte[] {
0x53, //push ebx
0x51, //push ecx
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xB3, 0x01, //mov bl, 1
0xD2, 0xE3, //shl bl, cl
0xEC, //in al, dx
0x08, 0xD8, //or al, bl
0xEE, //out dx, al
0x59, //pop ecx
0x5B //pop ebx
};
return InjectASM<WriteBitFunc>(code);
}
static WriteBitFunc GetClearBitHandler()
{
// 读出字节,取消指定位后重新写回去
var code = new Byte[] {
0x53, //push ebx
0x51, //push ecx
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xB3, 0x01, //mov bl, 1
0xD2, 0xE3, //shl bl, cl
0xF6, 0xD3, //not bl
0xEC, //in al, dx
0x20, 0xD8, //and al, bl
0xEE, //out dx, al
0x59, //pop ecx
0x5B, //pop ebx
};
return InjectASM<WriteBitFunc>(code);
}
public delegate void WriteBitFunc(Int16 address, Byte bit);
#endregion
#region 注入汇编
static T InjectASM<T>(Byte[] code)
{
// 汇编指令
var code1 = new Byte[] {
0x55, //push ebp
0x8B, 0xEC, //mov ebp, esp
0x52, //push edx
};
var code2 = new Byte[] {
0x5A, //pop edx
0x8B, 0xE5, //mov esp, ebp
0x5D, //pop ebp
0xC3 //ret
};
//var cbs = new Byte[code1.Length + code.Length + code2.Length];
var ms = new MemoryStream();
ms.Write(code1, 0, code1.Length);
ms.Write(code, 0, code.Length);
ms.Write(code2, 0, code2.Length);
code = ms.ToArray();
// 分配内存
var ptr = Marshal.AllocHGlobal(code.Length);
// 写入汇编指令
Marshal.Copy(code, 0, ptr, code.Length);
// 设为可执行
VirtualProtectExecute(ptr, code.Length);
Console.WriteLine("0x{0:X8}", ptr.ToInt32());
Console.ReadKey(true);
// 转为委托
return (T)(Object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
}
#endregion
#region 辅助
//[DllImport("kernel32.dll", SetLastError = true)]
//static extern int VirtualQueryEx(int hProcess, ref object lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int flNewProtect, ref int lpflOldProtect);
static Boolean VirtualProtectExecute(IntPtr address, Int32 size)
{
const Int32 PAGE_EXECUTE_READWRITE = 0x40;
Int32 old = 0;
return VirtualProtectEx(Process.GetCurrentProcess().Handle, address, size, PAGE_EXECUTE_READWRITE, ref old) == 0;
}
#endregion
}
}
在之前的博文 C#与VC相互调用之C#调用VC的DLL https://blog.csdn.net/xinxin_2011/article/details/86704660 里面讲了C#程序如何调用VC的DLL,这里我们来介绍VC程序调用C#的DLL。
项目创建
打开VS2010,因为涉及到两个程序,这里先创建一个空的解决方案:
然后往里面添加一个C#的DLL项目:
选择“类库”项目模板:
点击完成后生成如下文件:
默认生成的是Class1类,我们改名为“CSharpDll”,并添加如下代码:
接下来再创建一个VC项目,来测试DLL的调用:
这里创建一个基于对话框的MFC程序:
点击下一步,只选一个粗框架就可以了:
继续下一步,只勾选“公共控件清单”即可:
按照默认的名字生成类文件:
点击完成后,自动生成如下项目文件:
编写测试代码
简单修改下VC页面视图:
其中“调用C#的库”按钮ID为ID_CSHARPDLL_BTN,编辑框的ID为IDC_EDIT_RES。双击按钮,添加处理函数:
上面代码会有很多划红线的错误,因为用到了gcnew和System::String等公共语言运行库,所以得在项目属性中添加“公共语言运行时支持”:
此外注意文件上方要添加C#库的引用:
#using "../CSharpLibrary/bin/Debug/CSharpLibrary.dll"
using namespace CSharpLibrary;
这里注意路径的写法,默认当前路径是TestCSharpDll目录,而CSharpLibrary与TestCSharpDll同在一个解决方案目录中,生成的库在CSharpLibrary的bin/Debug目录下,所以这样写。
先别着急编译,因为VC程序要调用DLL必须保证生成的exe和dll文件在同一目录,所以需要改一下VC程序生成exe的路径:
写好后把把VC程序设置为启动项目:
设置好之后就可以编译了,成功后生成如下文件:
看到exe和dll都生成了就可以运行程序进行测试了:
可以看到VC和dll的交互都正常,如果没出现正确结果,请仔细检查路径设置的是否正确。
细节说明
调用测试完了,有些细节需要说明一下,看代码:
System::String ^proName = gcnew System::String(L"张三");
这里的字符串传参为什么是L"张三"呢?因为用到的是Unicode字符集,前面加上L代码是宽字符,如果对字符集不太了解的,可以参见我之前文章 VS下使用多字符集编码和Unicode字符集编码的总结 https://blog.csdn.net/xinxin_2011/article/details/84985083
顺便再提一下字符串变量转换的时候用到的强制转换:
CString str = (CString)res;
那位说这样强制转换觉得不太安全,那么CString有没有构造函数传参System::String呢?因为是宽字符,所以得看CStringT的源代码,CStringT中有一个传入System String的构造函数:
// This template will compile only for
// class SystemString == System::String
#if defined(__cplusplus_cli)
template <class SystemString>
CStringT( SystemString^ pString ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
cli::pin_ptr<const System::Char> pChar = PtrToStringChars( pString );
const wchar_t *psz = pChar;
*this = psz;
}
#elif defined(_MANAGED)
好了,既然有这样的构造函数,我们就可以替代强制转换了,改为如下代码:
VC调用C#的DLL显示界面
上面只是介绍了简单的字符串传递,那么VC能不能调用C#的Dll中的界面呢?下面来测试一下,在CSharpLibrary项目中添加一个界面类:
然后编辑窗体视图如下:
然后修改CSharpDll类,添加调用界面的函数:
最后在VC的OnBnClickedCsharpdllBtn函数中添加调用的代码:
看一下运行的结果:
OK,一切正常。
Object.ReferenceEquals()方法用于确定指定的Object实例是否为同一实例。此方法不能被覆盖。因此,如果用户要测试两个对象引用是否相等,并且不确定是否要执行Equals方法,则可以调用ReferenceEquals方法。
用法: public static bool Object.ReferenceEquals (object ob1, object ob2);
C# 常用API函数大全
常用Windows API
1. API之网络函数
2. API之消息函数
3. API之文件处理函数
4. API之打印函数
5. API之文本和字体函数
6. API之菜单函数
7. API之位图、图标和光栅运算函数
8. API之绘图函数
9. API之设备场景函数
10. API之硬件与系统函数
11. API之进程和线程函数
12. API之控件与消息函数
C#中通过Process运行程序如何获取进程的标准输出
在用C#写一个项目中的工具程序时,需要在C#程序中运行一个命令行的程序,同时将程序的命令行标准输出获取到并显示在指定的文本框中。
查找相关资料找到以下办法,供大家参考。
在创建Process的时候,通过如下方式来实现该功能。
首先,创建ProcessStartInfo:
var p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
然后,用上面创建好的启动信息来启动进程,如下:
p.Start();
while (!p.StandardOutput.EndOfStream)
{
string line = p.StandardOutput.ReadLine();
// do something with line
}
另外,也可以参照以下代码,采用同步或异步方式来运行程序,获取命令行标准输出的内容。
同步方式的代码:
static void runCommand()
{
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
//* Read the output (or the error)
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
string err = process.StandardError.ReadToEnd();
Console.WriteLine(err);
process.WaitForExit();
}
异步方式的代码:
static void runCommand()
{
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process and handlers
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
C#Post接口时如何忽略掉SSL证书验证或者添加ssl证书
解决办法:
C#:
第一种办法:代码调用时需在调用地址前加忽略掉ssl验证这段代码,如下:
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
整块代码如下:
public static string Post(string PostUrl, string Parameters)
{
string content = string.Empty;
try
{
//转换为字节数组
byte[] bytesRequestData = Encoding.UTF8.GetBytes(Parameters);
//跳过ssl验证
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
//path不是登录界面,是登录界面向服务器提交数据的界面
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(PostUrl);
myReq.Method = "post";
myReq.ContentType = "application/json; charset=UTF-8";
myReq.Headers.Add("用户名", "####");
myReq.Headers.Add("密码", "###");
//填充POST数据
myReq.ContentLength = bytesRequestData.Length;
Stream requestStream = myReq.GetRequestStream();
requestStream.Write(bytesRequestData, 0, bytesRequestData.Length);
requestStream.Close();
//发送POST数据请求服务器
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
//获取服务器返回信息
Stream myStream = HttpWResp.GetResponseStream();
StreamReader reader = new StreamReader(myStream, Encoding.UTF8);
content = reader.ReadToEnd();
reader.Close();
HttpWResp.Close();
}
catch (Exception ex)
{
content = ex.ToString();
}
return content;
}
第二种办法:
post接口时添加ssl证书:
//Certificates
X509Certificate2 x509Certificate2 = new X509Certificate2("C:\\Users\\linpa\\Desktop\\预生产证书认证导入教程\\cnooctrm.pem");
myReq.ClientCertificates.Add(x509Certificate2);
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
上述为该模块的主要代码,完整代码如下:
#region POST提交参数
/// <summary>
/// POST提交参数
/// </summary>
/// <param name="PostUrl">POST的地址,需要传送的地址</param>
/// <param name="Parameters">POST提交参数,例如“client_id=2866517568&client_secret=9c”和get的链接类似</param>
/// <returns></returns>
public static string Post(string PostUrl, string Parameters)
{
string content = string.Empty;
try
{
//转换为字节数组
byte[] bytesRequestData = Encoding.UTF8.GetBytes(Parameters);
//path不是登录界面,是登录界面向服务器提交数据的界面
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(PostUrl);
myReq.Method = "post";
myReq.ContentType = "application/json; charset=UTF-8";
myReq.Headers.Add("用户名", "####");
myReq.Headers.Add("密码", "###");
//Certificates
X509Certificate2 x509Certificate2 = new X509Certificate2("C:\\Users\\linpa\\Desktop\\预生产证书认证导入教程\\cnooctrm.pem");
myReq.ClientCertificates.Add(x509Certificate2);
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
//myReq.ProtocolVersion = HttpVersion.Version10;
//DefaultConnectionLimit是默认的2,而当前的Http的connection用完了,导致后续的GetResponse或GetRequestStream超时死掉
#region 如果报超时的错,可以把这两个注释去掉试一下
//DefaultConnectionLimit是默认的2,而当前的Http的connection用完了,导致后续的GetResponse或GetRequestStream超时死掉
//System.Net.ServicePointManager.DefaultConnectionLimit = 200;
//myReq.Timeout = 5 * 60 * 1000;//ms
#endregion
//填充POST数据
myReq.ContentLength = bytesRequestData.Length;
Stream requestStream = myReq.GetRequestStream();
requestStream.Write(bytesRequestData, 0, bytesRequestData.Length);
requestStream.Close();
//发送POST数据请求服务器
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
//获取服务器返回信息
Stream myStream = HttpWResp.GetResponseStream();
StreamReader reader = new StreamReader(myStream, Encoding.UTF8);
content = reader.ReadToEnd();
reader.Close();
HttpWResp.Close();
}
catch (Exception ex)
{
content = ex.ToString();
}
return content;
}
public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{ // 总是接受
return true;
}
#endregion
VS2013打不开nuget
工具-Nuget程序包管理器-程序包管理器控制台,输入以下命令:
[Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol-bOR [Net.SecurityProtocolType]::Tls12
c# URL Protocol 调用 给winform exe传参数
你可以使用URL协议(URL Protocol)来调用一个WinForms应用程序,并向其传递参数。URL Protocol是一种在Windows中注册的自定义URL方案,允许你通过URL来启动应用程序并传递参数。以下是实现这个过程的一般步骤:
1. **在注册表中为你的应用程序定义URL Protocol**:
在注册表中创建一个新的键(通常在`HKEY_CLASSES_ROOT`下),以定义你的自定义URL Protocol。例如,你可以创建一个名为`myapp`的键,并设置其默认值为一个描述你的应用程序的字符串。然后,在该键下创建一个名为`shell`的子键,并在其中创建一个名为`open`的子键,最终设置`open`子键的默认值为你的应用程序的可执行文件路径。
下面是一个示例注册表条目的样式:
```
HKEY_CLASSES_ROOT
└── myapp
└── (默认) = "URL:My Application Protocol"
└── URL Protocol = ""
└── shell
└── open
└── command
└── (默认) = "C:\Path\To\Your\WinFormsApp.exe %1"
```
在上面的示例中,`myapp`是你的自定义URL Protocol名称,`C:\Path\To\Your\WinFormsApp.exe`是你的WinForms应用程序的可执行文件路径。`%1`表示传递给应用程序的参数。
2. **在你的WinForms应用程序中处理传递的参数**:
在你的WinForms应用程序中,你需要处理从URL传递的参数。这可以通过在`Main`函数或`Form`的构造函数中获取命令行参数来完成。例如,在`Main`函数中,你可以使用`args`参数获取传递的参数:
```csharp
static void Main(string[] args)
{
// args数组包含传递的参数
if (args.Length > 0)
{
string parameter = args[0];
// 处理传递的参数
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
```
你可以将`parameter`传递给你的主窗体或其他需要使用参数的部分。
3. **通过URL调用你的应用程序**:
现在,你可以通过URL来调用你的应用程序并传递参数。例如,如果你的自定义URL Protocol名称为`myapp`,你可以使用类似以下的URL来启动你的应用程序并传递参数:
```
myapp://your_parameter_value
```
当用户点击这个URL或者在命令行中输入它时,你的应用程序将启动,并且可以在其中获取和处理`your_parameter_value`参数。
请注意,使用URL Protocol调用应用程序需要小心处理安全性问题,确保只接受来自可信来源的参数,并验证输入以防止潜在的安全风险。
在C#中,你可以使用`Microsoft.Win32.Registry`类来定义URL Protocol并注册应用程序以处理它。以下是一个示例代码,演示如何在注册表中定义URL Protocol:
using Microsoft.Win32;
using System;
class Program
{
static void Main(string[] args)
{
// 定义你的URL Protocol名称
string protocolName = "myapp";
try
{
// 创建或打开HKEY_CLASSES_ROOT下的URL Protocol键
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(protocolName))
{
// 设置默认值为描述你的协议的字符串
key.SetValue(null, "URL: My Application Protocol");
// 创建一个子键用于处理打开协议的操作
using (RegistryKey commandKey = key.CreateSubKey("shell\\open\\command"))
{
// 设置默认值为你的应用程序可执行文件的路径,包括 "%1" 用于参数
string appPath = "C:\\Path\\To\\Your\\WinFormsApp.exe \"%1\"";
commandKey.SetValue(null, appPath);
}
}
Console.WriteLine("URL Protocol已成功定义。");
}
catch (Exception ex)
{
Console.WriteLine("定义URL Protocol时出现错误:" + ex.Message);
}
}
}
```
请将上述代码中的`protocolName`替换为你希望定义的URL Protocol名称,将`appPath`替换为你的WinForms应用程序的可执行文件路径。执行此代码后,你的应用程序将能够处理与`myapp://`相关的URL,并可以从URL中获取参数。
请注意,在执行此代码之前,请确保你有足够的权限修改注册表。此外,URL Protocol名称应该是唯一的,不会与其他应用程序冲突。最后,遵循最佳实践来验证和处理来自URL的参数以确保安全性。
WebClient HttpWebRequest等访问https站点SSL错误处理
加入一下语句解决
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
关于C#的反射 Assembly.Load这个通过字节流加载dll,如何解决dll所依赖的dll问题
使用 Assembly.Load(byte[]) 加载程序集时,需要处理它所依赖的其他 DLL 文件。 这是因为 Assembly.Load 只加载指定的程序集,而不会自动加载其依赖项。
为了解决这个问题,您可以采取以下几种方法:
1. 预加载依赖项:
在加载主程序集之前,预先加载所有它依赖的 DLL 文件。 您可以使用 Assembly.Load 或 Assembly.LoadFrom 方法来加载这些依赖项。
// 获取主程序集的字节数组
byte[] mainAssemblyBytes = ...;
// 加载依赖项
Assembly dependencyAssembly = Assembly.LoadFrom("Dependency.dll");
// 加载主程序集
Assembly mainAssembly = Assembly.Load(mainAssemblyBytes);
优点: 简单直接。
缺点: 需要事先知道所有依赖项,如果依赖关系复杂,可能会很麻烦。
2. 处理 AppDomain.AssemblyResolve 事件:
当 CLR 尝试加载程序集但找不到时,会触发 AppDomain.AssemblyResolve 事件。您可以在事件处理程序中动态加载所需的 DLL 文件。
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name + ".dll";
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyName);
if (File.Exists(assemblyPath))
{
return Assembly.LoadFrom(assemblyPath);
}
return null;
};
// 加载主程序集
Assembly mainAssembly = Assembly.Load(mainAssemblyBytes);
优点: 更加灵活,可以在运行时动态加载依赖项。
缺点: 需要编写额外的代码来处理事件。
3. 将所有 DLL 文件打包到单个程序集中:
可以使用 ILMerge 或其他工具将主程序集及其所有依赖项合并到一个程序集中。
优点: 简化部署和加载过程。
缺点: 会增加程序集的大小,并可能导致版本冲突。
选择哪种方法取决于您的具体情况:
如果您的应用程序相对简单,依赖项较少,则预加载依赖项可能就足够了。
如果您的应用程序很复杂,依赖关系很多,或者您需要在运行时动态加载依赖项,则最好使用 AppDomain.AssemblyResolve 事件。
如果您希望简化部署,则可以考虑将所有 DLL 文件打包到单个程序集中。
希望以上信息对您有所帮助! 如果您还有其他问题,请随时提出。
C#热键的使用
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace HelloHotKey
{
public partial class Form1 : Form
{
private const int WM_HOTKEY = 0x0312;
private const int MOD_CONTROL = 0x0002;
private const int MOD_SHIFT = 0x0004;
private int _shortcutId = 100; // 自定义的快捷键ID
[DllImport("user32.dll", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
protected override void WndProc(ref Message m)
{
// 检查是否是快捷键消息
if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == _shortcutId)
{
MessageBox.Show("你按了Ctrl + Shift + A");
}
else
{
base.WndProc(ref m);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// 注册快捷键
if (!RegisterHotKey(this.Handle, _shortcutId, MOD_CONTROL | MOD_SHIFT, 0x41)) // 0x41 是字母A的虚拟键码
{
MessageBox.Show("无法注册快捷键");
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
}
private void Form1_HelpButtonClicked(object sender, System.ComponentModel.CancelEventArgs e)
{
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// 取消注册快捷键
UnregisterHotKey(this.Handle, _shortcutId);
}
}
}
C#模拟发送全局热键的代码
在C#中模拟发送全局热键通常涉及到使用Windows API函数来模拟按键操作。你可以使用 SendInput 函数来模拟按键的按下和释放,从而达到发送全局热键的目的。
下面是一个示例代码,展示了如何在C#中模拟发送全局热键 Ctrl + Shift + A。
using System.Runtime.InteropServices;
public class KeyboardSimulator
{
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public const byte VK_UP = 0x26;
public const byte VK_DOWN = 0x28;
public const byte VK_LEFT = 0x25;
public const byte VK_RIGHT = 0x27;
public const byte VK_CONTROL = 0x11;
public const byte VK_SHIFT = 0x10;
public const int KEYEVENTF_EXTENDEDKEY = 0x1;
public const int KEYEVENTF_KEYUP = 0x2;
public static void SimulateKeyPress(byte key)
{
keybd_event(key, 0x45, 0, 0);
keybd_event(key, 0x45, KEYEVENTF_KEYUP, 0);
}
public static void SimulateKeyPress(byte[] keys)
{
for (int i = 0; i < keys.Length; i++)
{
keybd_event(keys[i], 0x45, 0, 0);
}
for (int i = 0; i < keys.Length; i++)
{
keybd_event(keys[i], 0x45, KEYEVENTF_KEYUP, 0);
}
}
}
KeyboardSimulator.SimulateKeyPress(new byte[] { KeyboardSimulator.VK_CONTROL, KeyboardSimulator.VK_SHIFT, (byte)'A' });
特别注意输入是大写'A'实际输入为小写a
如要模拟输入大写A那么
byte key=(byte)'A';
keybd_event(VK_SHIFT, 0, 0, 0); // 模拟按下 Shift 键
keybd_event(key, 0x45, 0, 0);
keybd_event(key, 0x45, KEYEVENTF_KEYUP, 0);
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
C#模拟鼠标点击
public class MouseSimulator
{
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
// 鼠标事件标志
private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; // 左键按下
private const uint MOUSEEVENTF_LEFTUP = 0x0004; // 左键抬起
private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; // 右键按下
private const uint MOUSEEVENTF_RIGHTUP = 0x0010; // 右键抬起
/// <summary>
/// 移动鼠标到指定坐标
/// </summary>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
static public void MoveMouseToPoint(int x, int y)
{
SetCursorPos(x, y);
}
/// <summary>
/// 模拟左键点击
/// </summary>
static public void LeftClick()
{
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
/// <summary>
/// 在指定坐标模拟左键点击
/// </summary>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
static public void LeftClickAt(int x, int y)
{
MoveMouseToPoint(x, y);
LeftClick();
}
}
一个完整的键盘鼠标模拟封装
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace HelloHotKey
{
#region 虚拟代码(键盘鼠标)
public class VKCODE
{
public const byte VK_LBUTTON = 0x01;//鼠标左键
public const byte VK_RBUTTON = 0x02;//鼠标右键
public const byte VK_CANCEL = 0x03;//控制中断处理
public const byte VK_MBUTTON = 0x04;//鼠标中键
public const byte VK_XBUTTON1 = 0x05;//X1 鼠标按钮
public const byte VK_XBUTTON2 = 0x06;//X2 鼠标按钮
//public const byte VK_ = 0x07;//保留
public const byte VK_BACK = 0x08;//BACKSPACE 键
public const byte VK_TAB = 0x09;//Tab 键
//public const byte VK_ = 0x0A;//预留
//public const byte VK_ = 0x0B;//预留
public const byte VK_CLEAR = 0x0C;//CLEAR 键
public const byte VK_RETURN = 0x0D;//Enter 键
//public const byte VK_ = 0x0E;//未分配
//public const byte VK_ = 0x0F;//未分配
public const byte VK_SHIFT = 0x10;//SHIFT 键
public const byte VK_CONTROL = 0x11;//CTRL 键
public const byte VK_MENU = 0x12;//Alt 键
public const byte VK_PAUSE = 0x13;//PAUSE 键
public const byte VK_CAPITAL = 0x14;//CAPS LOCK 键
public const byte VK_KANA = 0x15;//IME Kana 模式
public const byte VK_HANGUL = 0x15;//IME Hanguel 模式
public const byte VK_IME_ON = 0x16;//IME 打开
public const byte VK_JUNJA = 0x17;//IME Junja 模式
public const byte VK_FINAL = 0x18;//IME 最终模式
public const byte VK_HANJA = 0x19;//IME Hanja 模式
public const byte VK_KANJI = 0x19;//IME Kanji 模式
public const byte VK_IME_OFF = 0x1A;//IME 关闭
public const byte VK_ESCAPE = 0x1B;//ESC 键
public const byte VK_CONVERT = 0x1C;//IME 转换
public const byte VK_NONCONVERT = 0x1D;//IME 不转换
public const byte VK_ACCEPT = 0x1E;//IME 接受
public const byte VK_MODECHANGE = 0x1F;//IME 模式更改请求
public const byte VK_SPACE = 0x20;//空格键
public const byte VK_PRIOR = 0x21;//PAGE UP 键
public const byte VK_NEXT = 0x22;//PAGE DOWN 键
public const byte VK_END = 0x23;//END 键
public const byte VK_HOME = 0x24;//HOME 键
public const byte VK_LEFT = 0x25;//LEFT ARROW 键
public const byte VK_UP = 0x26;//UP ARROW 键
public const byte VK_RIGHT = 0x27;//RIGHT ARROW 键
public const byte VK_DOWN = 0x28;//DOWN ARROW 键
public const byte VK_SELECT = 0x29;//SELECT 键
public const byte VK_PRINT = 0x2A;//PRINT 键
public const byte VK_EXECUTE = 0x2B;//EXECUTE 键
public const byte VK_SNAPSHOT = 0x2C;//PRINT SCREEN 键
public const byte VK_INSERT = 0x2D;//INS 键
public const byte VK_DELETE = 0x2E;//DEL 键
public const byte VK_HELP = 0x2F;//HELP 键
public const byte VK_D0 = 0x30;//0 键
public const byte VK_D1 = 0x31;//1 键
public const byte VK_D2 = 0x32;//2 键
public const byte VK_D3 = 0x33;//3 键
public const byte VK_D4 = 0x34;//4 键
public const byte VK_D5 = 0x35;//5 键
public const byte VK_D6 = 0x36;//6 键
public const byte VK_D7 = 0x37;//7 键
public const byte VK_D8 = 0x38;//8 键
public const byte VK_D9 = 0x39;//9 键
//public const byte VK_ = 0x3A;//未定义
//public const byte VK_ = 0x3B;//未定义
//public const byte VK_ = 0x3C;//未定义
//public const byte VK_ = 0x3D;//未定义
//public const byte VK_ = 0x3E;//未定义
//public const byte VK_ = 0x3F;//未定义
//public const byte VK_ = 0x40;//未定义
public const byte VK_A = 0x41;//A 键
public const byte VK_B = 0x42;//B 键
public const byte VK_C = 0x43;//C 键
public const byte VK_D = 0x44;//D 键
public const byte VK_E = 0x45;//E 键
public const byte VK_F = 0x46;//F 键
public const byte VK_G = 0x47;//G 键
public const byte VK_H = 0x48;//H 键
public const byte VK_I = 0x49;//I 键
public const byte VK_J = 0x4A;//J 键
public const byte VK_K = 0x4B;//K 键
public const byte VK_L = 0x4C;//L 键
public const byte VK_M = 0x4D;//M 键
public const byte VK_N = 0x4E;//N 键
public const byte VK_O = 0x4F;//O 键
public const byte VK_P = 0x50;//P 键
public const byte VK_Q = 0x51;//Q 键
public const byte VK_R = 0x52;//R 键
public const byte VK_S = 0x53;//S 键
public const byte VK_T = 0x54;//T 键
public const byte VK_U = 0x55;//U 键
public const byte VK_V = 0x56;//V 键
public const byte VK_W = 0x57;//W 键
public const byte VK_X = 0x58;//X 键
public const byte VK_Y = 0x59;//Y 键
public const byte VK_Z = 0x5A;//Z 键
public const byte VK_LWIN = 0x5B;//左 Windows 键
public const byte VK_RWIN = 0x5C;//右侧 Windows 键
public const byte VK_APPS = 0x5D;//应用程序密钥
//public const byte VK_ = 0x5E;//预留
public const byte VK_SLEEP = 0x5F;//计算机休眠键
public const byte VK_NUMPAD0 = 0x60;//数字键盘 0 键
public const byte VK_NUMPAD1 = 0x61;//数字键盘 1 键
public const byte VK_NUMPAD2 = 0x62;//数字键盘 2 键
public const byte VK_NUMPAD3 = 0x63;//数字键盘 3 键
public const byte VK_NUMPAD4 = 0x64;//数字键盘 4 键
public const byte VK_NUMPAD5 = 0x65;//数字键盘 5 键
public const byte VK_NUMPAD6 = 0x66;//数字键盘 6 键
public const byte VK_NUMPAD7 = 0x67;//数字键盘 7 键
public const byte VK_NUMPAD8 = 0x68;//数字键盘 8 键
public const byte VK_NUMPAD9 = 0x69;//数字键盘 9 键
public const byte VK_MULTIPLY = 0x6A;//乘号键
public const byte VK_ADD = 0x6B;//加号键
public const byte VK_SEPARATOR = 0x6C;//分隔符键
public const byte VK_SUBTRACT = 0x6D;//减号键
public const byte VK_DECIMAL = 0x6E;//句点键
public const byte VK_DIVIDE = 0x6F;//除号键
public const byte VK_F1 = 0x70;//F1 键
public const byte VK_F2 = 0x71;//F2 键
public const byte VK_F3 = 0x72;//F3 键
public const byte VK_F4 = 0x73;//F4 键
public const byte VK_F5 = 0x74;//F5 键
public const byte VK_F6 = 0x75;//F6 键
public const byte VK_F7 = 0x76;//F7 键
public const byte VK_F8 = 0x77;//F8 键
public const byte VK_F9 = 0x78;//F9 键
public const byte VK_F10 = 0x79;//F10 键
public const byte VK_F11 = 0x7A;//F11 键
public const byte VK_F12 = 0x7B;//F12 键
public const byte VK_F13 = 0x7C;//F13 键
public const byte VK_F14 = 0x7D;//F14 键
public const byte VK_F15 = 0x7E;//F15 键
public const byte VK_F16 = 0x7F;//F16 键
public const byte VK_F17 = 0x80;//F17 键
public const byte VK_F18 = 0x81;//F18 键
public const byte VK_F19 = 0x82;//F19 键
public const byte VK_F20 = 0x83;//F20 键
public const byte VK_F21 = 0x84;//F21 键
public const byte VK_F22 = 0x85;//F22 键
public const byte VK_F23 = 0x86;//F23 键
public const byte VK_F24 = 0x87;//F24 键
//public const byte VK_ = 0x88;//保留
//public const byte VK_ = 0x89;//保留
//public const byte VK_ = 0x8A;//保留
//public const byte VK_ = 0x8B;//保留
//public const byte VK_ = 0x8C;//保留
//public const byte VK_ = 0x8D;//保留
//public const byte VK_ = 0x8E;//保留
//public const byte VK_ = 0x8F;//保留
public const byte VK_NUMLOCK = 0x90;//NUM LOCK 键
public const byte VK_SCROLL = 0x91;//SCROLL LOCK 键
//public const byte VK_ = 0x92;//OEM 特有
//public const byte VK_ = 0x93;//OEM 特有
//public const byte VK_ = 0x94;//OEM 特有
//public const byte VK_ = 0x95;//OEM 特有
//public const byte VK_ = 0x96;//OEM 特有
//public const byte VK_ = 0x97;//未分配
//public const byte VK_ = 0x98;//未分配
//public const byte VK_ = 0x99;//未分配
//public const byte VK_ = 0x9A;//未分配
//public const byte VK_ = 0x9B;//未分配
//public const byte VK_ = 0x9C;//未分配
//public const byte VK_ = 0x9D;//未分配
//public const byte VK_ = 0x9E;//未分配
//public const byte VK_ = 0x9F;//未分配
public const byte VK_LSHIFT = 0xA0;//左 SHIFT 键
public const byte VK_RSHIFT = 0xA1;//右 SHIFT 键
public const byte VK_LCONTROL = 0xA2;//左 Ctrl 键
public const byte VK_RCONTROL = 0xA3;//右 Ctrl 键
public const byte VK_LMENU = 0xA4;//左 ALT 键
public const byte VK_RMENU = 0xA5;//右 ALT 键
public const byte VK_BROWSER_BACK = 0xA6;//浏览器后退键
public const byte VK_BROWSER_FORWARD = 0xA7;//浏览器前进键
public const byte VK_BROWSER_REFRESH = 0xA8;//浏览器刷新键
public const byte VK_BROWSER_STOP = 0xA9;//浏览器停止键
public const byte VK_BROWSER_SEARCH = 0xAA;//浏览器搜索键
public const byte VK_BROWSER_FAVORITES = 0xAB;//浏览器收藏键
public const byte VK_BROWSER_HOME = 0xAC;//浏览器“开始”和“主页”键
public const byte VK_VOLUME_MUTE = 0xAD;//静音键
public const byte VK_VOLUME_DOWN = 0xAE;//音量减小键
public const byte VK_VOLUME_UP = 0xAF;//音量增加键
public const byte VK_MEDIA_NEXT_TRACK = 0xB0;//下一曲目键
public const byte VK_MEDIA_PREV_TRACK = 0xB1;//上一曲目键
public const byte VK_MEDIA_STOP = 0xB2;//停止媒体键
public const byte VK_MEDIA_PLAY_PAUSE = 0xB3;//播放/暂停媒体键
public const byte VK_LAUNCH_MAIL = 0xB4;//启动邮件键
public const byte VK_LAUNCH_MEDIA_SELECT = 0xB5;//选择媒体键
public const byte VK_LAUNCH_APP1 = 0xB6;//启动应用程序 1 键
public const byte VK_LAUNCH_APP2 = 0xB7;//启动应用程序 2 键
//public const byte VK_ = 0xB8;//预留
//public const byte VK_ = 0xB9;//预留
public const byte VK_OEM_1 = 0xBA;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键;:
public const byte VK_OEM_PLUS = 0xBB;//对于任何国家/地区,键+
public const byte VK_OEM_COMMA = 0xBC;//对于任何国家/地区,键,
public const byte VK_OEM_MINUS = 0xBD;//对于任何国家/地区,键-
public const byte VK_OEM_PERIOD = 0xBE;//对于任何国家/地区,键.
public const byte VK_OEM_2 = 0xBF;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键/?
public const byte VK_OEM_3 = 0xC0;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键`~
//public const byte VK_ = 0xC1;//保留
//public const byte VK_ = 0xC2;//保留
//public const byte VK_ = 0xC3;//保留
//public const byte VK_ = 0xC4;//保留
//public const byte VK_ = 0xC5;//保留
//public const byte VK_ = 0xC6;//保留
//public const byte VK_ = 0xC7;//保留
//public const byte VK_ = 0xC8;//保留
//public const byte VK_ = 0xC9;//保留
//public const byte VK_ = 0xCA;//保留
//public const byte VK_ = 0xCB;//保留
//public const byte VK_ = 0xCC;//保留
//public const byte VK_ = 0xCD;//保留
//public const byte VK_ = 0xCE;//保留
//public const byte VK_ = 0xCF;//保留
//public const byte VK_ = 0xD0;//保留
//public const byte VK_ = 0xD1;//保留
//public const byte VK_ = 0xD2;//保留
//public const byte VK_ = 0xD3;//保留
//public const byte VK_ = 0xD4;//保留
//public const byte VK_ = 0xD5;//保留
//public const byte VK_ = 0xD6;//保留
//public const byte VK_ = 0xD7;//保留
//public const byte VK_ = 0xD8;//保留
//public const byte VK_ = 0xD9;//保留
//public const byte VK_ = 0xDA;//保留
public const byte VK_OEM_4 = 0xDB;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键[{
public const byte VK_OEM_5 = 0xDC;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键\\|
public const byte VK_OEM_6 = 0xDD;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键]}
public const byte VK_OEM_7 = 0xDE;//用于杂项字符;它可能因键盘而异。 对于美国标准键盘,键'"
public const byte VK_OEM_8 = 0xDF;//用于杂项字符;它可能因键盘而异。
//public const byte VK_ = 0xE0;//预留
//public const byte VK_ = 0xE1;//OEM 特有
public const byte VK_OEM_102 = 0xE2;//美国标准键盘上的 <> 键,或非美国 102 键键盘上的 \\| 键
//public const byte VK_ = 0xE3;//OEM 特有
//public const byte VK_ = 0xE4;//OEM 特有
public const byte VK_PROCESSKEY = 0xE5;//IME PROCESS 键
//public const byte VK_ = 0xE6;//OEM 特有
public const byte VK_PACKET = 0xE7;//用于将 Unicode 字符当作键击传递。 VK_PACKET 键是用于非键盘输入法的 32 位虚拟键值的低位字。 有关更多信息,请参阅 KEYBDINPUT、SendInput、WM_KEYDOWN 和 WM_KEYUP 中的注释
//public const byte VK_ = 0xE8;//未分配
//public const byte VK_ = 0xE9;//OEM 特有
//public const byte VK_ = 0xEA;//OEM 特有
//public const byte VK_ = 0xEB;//OEM 特有
//public const byte VK_ = 0xEC;//OEM 特有
//public const byte VK_ = 0xED;//OEM 特有
//public const byte VK_ = 0xEE;//OEM 特有
//public const byte VK_ = 0xEF;//OEM 特有
//public const byte VK_ = 0xF0;//OEM 特有
//public const byte VK_ = 0xF1;//OEM 特有
//public const byte VK_ = 0xF2;//OEM 特有
//public const byte VK_ = 0xF3;//OEM 特有
//public const byte VK_ = 0xF4;//OEM 特有
//public const byte VK_ = 0xF5;//OEM 特有
public const byte VK_ATTN = 0xF6;//Attn 键
public const byte VK_CRSEL = 0xF7;//CrSel 键
public const byte VK_EXSEL = 0xF8;//ExSel 键
public const byte VK_EREOF = 0xF9;//Erase EOF 键
public const byte VK_PLAY = 0xFA;//Play 键
public const byte VK_ZOOM = 0xFB;//Zoom 键
//public const byte VK_NONAME = 0xFC;//预留
public const byte VK_PA1 = 0xFD;//PA1 键
public const byte VK_OEM_CLEAR = 0xFE;//Clear 键
}
#endregion
#region window消息及其他常量
public class WindowsConstant
{
//按键状态
public const int KEYEVENTF_KEYDOWN = 0x0000; //键被按下
public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //是扩展键
public const int KEYEVENTF_KEYUP = 0x0002; //键被释放
public const int GWL_EXSTYLE = -20;
public const int WS_DISABLED = 0X8000000;
public const int WM_SETFOCUS = 0X0007;
//鼠标消息
public const int WM_MOUSEMOVE = 0x200;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_LBUTTONUP = 0x202;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_RBUTTONUP = 0x205;
public const int WM_RBUTTONDBLCLK = 0x206;
public const int WM_MBUTTONDOWN = 0x207;
public const int WM_MBUTTONUP = 0x208;
public const int WM_MOUSEWHEEL = 0x020A;
//键盘状态消息
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
// 鼠标状态
public const int MOUSEEVENTF_MOVE = 0x0001; // 移动鼠标位置
public const int MOUSEEVENTF_LEFTDOWN = 0x0002; // 按下左键
public const int MOUSEEVENTF_LEFTUP = 0x0004; // 松开左键
public const int MOUSEEVENTF_RIGHTDOWN = 0x0008; // 按下右键
public const int MOUSEEVENTF_RIGHTUP = 0x0010; // 松开右键
public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //中间按钮已关闭。
public const int MOUSEEVENTF_MIDDLEUP = 0x0040; //中间按钮已向上。
public const int MOUSEEVENTF_WHEEL = 0x0800; //滚轮按钮已旋转。
public const int MOUSEEVENTF_XDOWN = 0x0080; //按下了 X 按钮。
public const int MOUSEEVENTF_XUP = 0x0100; //已释放 X 按钮。
public const int MOUSEEVENTF_HWHEEL = 0x01000; //滚轮按钮倾斜。
public const int MOUSEEVENTF_ABSOLUTE = 0x8000; /* dx 和 dy 参数包含规范化的绝对坐标。
如果未设置,则这些参数包含相对数据:自上次报告的位置以来
的位置变化。无论哪种类型的鼠标或类似鼠标的设备(如果有)
连接到系统,都可以设置或不设置此标志。有关相对鼠标运动的
详细信息,请参阅以下“备注”部分。
*/
public const uint INPUT_MOUSE = 0x0004;
}
#endregion
#region 鼠标键盘输入的结构体
[StructLayout(LayoutKind.Sequential)]
internal struct Input
{
public int type;
public InputUnion U;
}
[StructLayout(LayoutKind.Explicit)]
internal struct InputUnion
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
/* dx、dy不是以象素为单位的,而是以鼠标设备移动量为单位的,它们之间的比值受鼠标移动速度设置的影响。
* dwFlags可以设置一个MOUSEEVENTF ABSOLUTE标志,这使得可以用另外一种方法移动标,
* 当dwFlags设置了MOUSEEVENTF ABSOLUTE标志,dx、dy为屏幕坐标值,表示将鼠标移动到dx,dy的位置,
* 但是这个坐标值也不是以象素为单位的。这个值的范围是0到65535(SFFFF),当dx等于0、dy等于0时表示屏幕的最左上角,
* 当dx等于65535、d等于65535时表示屏幕的最右下角,相当于将屏幕的宽和高分别65536等分。
* API函数GetSystemMetrics(SM_CXSCREEN-0)可以返回屏幕的宽度,函数GetSystemMetrics(SM_CYSCREEN=1)可以返回屏幕的高度,
* 利用屏幕的宽度和高度就可以将象素坐标换算成相应的dx、dy。注意: 这种换算最多会出现1象素的误差。
*/
public int dx; // 鼠标移动时的x轴坐标差(不是象素单位),在鼠标移动时有效
public int dy; // 鼠标移动时的y轴坐标差(不是象素单位),在鼠标移动时有效
public int mouseData; /* 鼠标滚轮滚动值,在滚动鼠标滚轮时有效。
当mouseData小于0时向下滚动,当mouseData大于0时向上滚动,
mouseData的绝对值一般设为120*/
public int dwFlags; /* dwFlags指定鼠标所进行的操作,例,MOUSEEVENTF_MOVE表示移动光标,
MOUSEEVENTF_LEFTDOWN表示按下鼠标左键,MOUSEEVENTF LEFTUP表示放开鼠标左键。
*/
public int time; // 时间戳,可以使用API函数GetTickCount的返回值,
public IntPtr dwExtraInfo; // 扩展信息,可以使用API函教GetMessageExtralnfo的返回值。
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
internal class InputType
{
public const int MOUSE = 0;
public const int KEYBOARD = 1;
public const int HARDWARE = 2;
}
#endregion
#region 鼠标键盘所用到的Window API
internal static class NativeMethods
{
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("User32.dll", EntryPoint = "SendInput", CharSet = CharSet.Auto)]
internal static extern UInt32 SendInput(UInt32 nInputs, Input[] pInputs, Int32 cbSize);
[DllImport("Kernel32.dll", EntryPoint = "GetTickCount", CharSet = CharSet.Auto)]
internal static extern int GetTickCount();
[DllImport("User32.dll", EntryPoint = "GetKeyState", CharSet = CharSet.Auto)]
internal static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
#endregion
#region 屏幕分辨率/尺寸
/// <summary>
/// 系统指标或系统配置设置,检索的所有维度都以像素为单位。
/// </summary>
public class SystemMetricsHelper
{
public const int SM_CXSCREEN = 0;//主显示器的屏幕宽度(以像素为单位)。 这是通过调用 GetDeviceCaps 获取的相同值,如下所示: GetDeviceCaps( hdcPrimaryMonitor, HORZRES)。
public const int SM_CYSCREEN = 1;//主显示器的屏幕高度(以像素为单位)。 这是通过调用 GetDeviceCaps 获取的相同值,如下所示: GetDeviceCaps( hdcPrimaryMonitor, VERTRES)。
public const int SM_CXVSCROLL = 2;//垂直滚动条的宽度(以像素为单位)。
public const int SM_CYHSCROLL = 3;//水平滚动条的高度(以像素为单位)。
public const int SM_CYCAPTION = 4;//描述文字区域的高度(以像素为单位)。窗口标题的高度(实际标题高度加上SM_CYBORDER)
public const int SM_CXBORDER = 5;//窗口边框的宽度(以像素为单位)。 这等效于具有 3D 外观的窗口的 SM_CXEDGE 值。
public const int SM_CYBORDER = 6;//窗口边框的高度(以像素为单位)。 这等效于具有 3D 外观的窗口的 SM_CYEDGE 值。
public const int SM_CXFIXEDFRAME = 7;//窗口周围具有描述文字但不是相当大的(以像素为单位)的框架的粗细。 SM_CXFIXEDFRAME是水平边框的高度,SM_CYFIXEDFRAME是垂直边框的宽度。
public const int SM_CXDLGFRAME = 7;//对话框边框宽度/此值与 SM_CXFIXEDFRAME 相同。
public const int SM_CYFIXEDFRAME = 8;//窗口周围具有描述文字但不是相当大的(以像素为单位)的框架的粗细。 SM_CXFIXEDFRAME是水平边框的高度,SM_CYFIXEDFRAME是垂直边框的宽度。
public const int SM_CYDLGFRAME = 8;//对话框边框高度/此值与 SM_CYFIXEDFRAME 相同。SM_CYFIXEDFRAME
public const int SM_CYVTHUMB = 9;//垂直滚动条上滑块的宽度/垂直滚动条中拇指框的高度(以像素为单位)。
public const int SM_CXHTHUMB = 10;//水平滚动条上滑块的宽度/水平滚动条中拇指框的宽度(以像素为单位)。
public const int SM_CXICON = 11;//图标的系统大宽度(以像素为单位)。 LoadIcon 函数只能加载具有SM_CXICON和SM_CYICON指定尺寸的图标。 有关详细信息 ,请参阅图标大小 。
public const int SM_CYICON = 12;//图标的系统高度(以像素为单位)。 LoadIcon 函数只能加载具有SM_CXICON和SM_CYICON指定尺寸的图标。 有关详细信息 ,请参阅图标大小 。
public const int SM_CXCURSOR = 13;//光标的标称宽度(以像素为单位)。
public const int SM_CYCURSOR = 14;//光标的标称高度(以像素为单位)。
public const int SM_CYMENU = 15;//单行菜单栏的高度(以像素为单位)。
public const int SM_CXFULLSCREEN = 16;//主显示器上全屏窗口的工作区宽度(以像素为单位)。 若要获取系统任务栏或应用程序桌面工具栏未遮挡的屏幕部分的坐标,请使用SPI_GETWORKAREA值调用 SystemParametersInfo 函数。
public const int SM_CYFULLSCREEN = 17;//主显示器上全屏窗口的工作区高度(以像素为单位)。 若要获取系统任务栏或应用程序桌面工具栏未遮挡的屏幕部分的坐标,请使用 SPI_GETWORKAREA 值调用 SystemParametersInfo 函数。
public const int SM_CYKANJIWINDOW = 18;//对于系统的双字节字符集版本,这是屏幕底部的汉字窗口的高度(以像素为单位)。
public const int SM_MOUSEPRESENT = 19;//如果安装了鼠标,则为非零值;否则为 0。 此值很少为零,因为支持虚拟鼠标,并且某些系统检测到端口的存在,而不是鼠标的存在。
public const int SM_CYVSCROLL = 20;//垂直滚动条上箭头位图的高度(以像素为单位)。
public const int SM_CXHSCROLL = 21;//水平滚动条上箭头位图的宽度(以像素为单位)。
public const int SM_DEBUG = 22;//如果安装了User.exe的调试版本,则为非零;否则为 0。
public const int SM_SWAPBUTTON = 23;//如果交换了鼠标左键和右键的含义,则为非零值;否则为 0。
public const int SM_CXMIN = 28;//窗口的最小宽度(以像素为单位)。
public const int SM_CYMIN = 29;//窗口的最小高度(以像素为单位)。
public const int SM_CXSIZE = 30;//窗口中按钮的宽度描述文字或标题栏(以像素为单位)。
public const int SM_CYSIZE = 31;//窗口中按钮的高度描述文字或标题栏(以像素为单位)。SM_CXSIZEFRAME
public const int SM_CXSIZEFRAME = 32;//可调整大小的窗口周边的大小边框的粗细(以像素为单位)。 SM_CXSIZEFRAME是水平边框的宽度,SM_CYSIZEFRAME是垂直边框的高度。此值与 SM_CXFRAME 相同。
public const int SM_CXFRAME = 32;//此值与 SM_CXSIZEFRAME 相同。
public const int SM_CYSIZEFRAME = 33;//可调整大小的窗口周边的大小边框的粗细(以像素为单位)。 SM_CXSIZEFRAME是水平边框的宽度,SM_CYSIZEFRAME是垂直边框的高度。此值与 SM_CYFRAME 相同。
public const int SM_CYFRAME = 33;//此值与 SM_CYSIZEFRAME 相同。
public const int SM_CXMINTRACK = 34;//窗口的最小跟踪宽度(以像素为单位)。 用户无法将窗口框架拖动到小于这些尺寸的大小。 窗口可以通过处理 WM_GETMINMAXINFO 消息来替代此值。
public const int SM_CYMINTRACK = 35;//窗口的最小跟踪高度(以像素为单位)。 用户无法将窗口框架拖动到小于这些尺寸的大小。 窗口可以通过处理 WM_GETMINMAXINFO 消息来替代此值。
public const int SM_CXDOUBLECLK = 36;//矩形围绕双击序列中第一次单击的位置的宽度(以像素为单位)。 第二次单击必须在由 SM_CXDOUBLECLK 和 SM_CYDOUBLECLK 定义的矩形内发生,
//系统才能将两次单击视为双击。 两次单击也必须在指定时间内发生。若要设置双击矩形的宽度,请使用SPI_SETDOUBLECLKWIDTH调用 SystemParametersInfo 。
public const int SM_CYDOUBLECLK = 37;//矩形围绕双击序列中第一次单击的位置的高度(以像素为单位)。 第二次单击必须在由 SM_CXDOUBLECLK 定义的矩形内发生,SM_CYDOUBLECLK系统会将两次单击视为双击。
//两次单击也必须在指定时间内发生。若要设置双击矩形的高度,请使用SPI_SETDOUBLECLKHEIGHT调用 SystemParametersInfo 。
public const int SM_CXICONSPACING = 38;//大图标视图中项的网格单元格的宽度(以像素为单位)。 每个项都适合在排列时按SM_CYICONSPACING SM_CXICONSPACING大小的矩形。 此值始终大于或等于 SM_CXICON。
public const int SM_CYICONSPACING = 39;//大图标视图中项的网格单元格的高度(以像素为单位)。 每个项都适合在排列时按SM_CYICONSPACING SM_CXICONSPACING大小的矩形。 此值始终大于或等于 SM_CYICON。
public const int SM_MENUDROPALIGNMENT = 40;//如果下拉菜单与相应的菜单栏项右对齐,则为非零值;如果菜单左对齐,则为 0。
public const int SM_PENWINDOWS = 41;//如果安装了 Microsoft Windows for Pen 计算扩展,则为非零值;否则为零。
public const int SM_DBCSENABLED = 42;//如果User32.dll支持 DBCS,则为非零值;否则为 0。
public const int SM_CMOUSEBUTTONS = 43;//鼠标上的按钮数;如果未安装鼠标,则为零。
public const int SM_SECURE = 44;//应忽略此系统指标;它始终返回 0。SM_CXEDGE
public const int SM_CXEDGE = 45;//三维边框的宽度(以像素为单位)。 此指标是SM_CXBORDER的三维对应指标。
public const int SM_CYEDGE = 46;//三维边框的高度(以像素为单位)。 这是SM_CYBORDER的三维对应项。
public const int SM_CXMINSPACING = 47;//最小化窗口的网格单元格的宽度(以像素为单位)。 每个最小化窗口在排列时适合此大小的矩形。 此值始终大于或等于 SM_CXMINIMIZED。
public const int SM_CYMINSPACING = 48;//最小化窗口的网格单元格的高度(以像素为单位)。 每个最小化窗口在排列时适合此大小的矩形。 此值始终大于或等于 SM_CYMINIMIZED。
public const int SM_CXSMICON = 49;//图标的系统小宽度(以像素为单位)。 小图标通常显示在窗口标题和小图标视图中。 有关详细信息 ,请参阅图标大小 。
public const int SM_CYSMICON = 50;//图标的系统小高度(以像素为单位)。 小图标通常显示在窗口标题和小图标视图中。 有关详细信息 ,请参阅图标大小 。
public const int SM_CYSMCAPTION = 51;//小描述文字的高度(以像素为单位)。
public const int SM_CXSMSIZE = 52;//小描述文字按钮的宽度(以像素为单位)。
public const int SM_CYSMSIZE = 53;//小描述文字按钮的高度(以像素为单位)。
public const int SM_CXMENUSIZE = 54;//菜单栏按钮的宽度,例如在多个文档界面中使用的子窗口关闭按钮(以像素为单位)。
public const int SM_CYMENUSIZE = 55;//菜单栏按钮(例如在多个文档界面中使用的子窗口关闭按钮)的高度(以像素为单位)。
public const int SM_ARRANGE = 56;//指定系统如何排列最小化窗口的标志。 有关详细信息,请参阅本主题中的“备注”部分。
public const int SM_CXMINIMIZED = 57;//最小化窗口的宽度(以像素为单位)。
public const int SM_CYMINIMIZED = 58;//最小化窗口的高度(以像素为单位)。
public const int SM_CXMAXTRACK = 59;//具有描述文字和大小调整边框(以像素为单位)的窗口的默认最大宽度。 此指标是指整个桌面。 用户无法将窗口框架拖动到大于这些尺寸的大小。 窗口可以通过处理 WM_GETMINMAXINFO 消息来替代此值。
public const int SM_CYMAXTRACK = 60;//具有描述文字和大小调整边框的窗口的默认最大高度(以像素为单位)。 此指标是指整个桌面。 用户无法将窗口框架拖动到大于这些尺寸的大小。 窗口可以通过处理 WM_GETMINMAXINFO 消息来替代此值。
public const int SM_CXMAXIMIZED = 61;//主显示监视器上最大化的顶级窗口的默认宽度(以像素为单位)。
public const int SM_CYMAXIMIZED = 62;//主显示监视器上最大化的顶级窗口的默认高度(以像素为单位)。
public const int SM_NETWORK = 63;//如果存在网络,则设置最小有效位;否则,将清除它。 其他位保留供将来使用。
public const int SM_CLEANBOOT = 67;//指定系统启动方式的 值:0 正常启动,1 故障安全启动,2 通过网络启动实现故障安全,故障安全启动(也称为 SafeBoot、安全模式或干净启动) 会绕过用户启动文件。
public const int SM_CXDRAG = 68;//鼠标指针在拖动操作开始之前可以移动的鼠标向下点任一侧的像素数。 这允许用户轻松单击并释放鼠标按钮,而不会无意中启动拖动操作。 如果此值为负值,则从鼠标向下点的左侧减去该值,并将其添加到其右侧。
public const int SM_CYDRAG = 69;//鼠标指针在拖动操作开始之前可以移动的鼠标向下点上方和下方的像素数。 这允许用户轻松单击并释放鼠标按钮,而不会无意中启动拖动操作。 如果此值为负值,则从鼠标向下点上方减去该值,并将其添加到其下方。
public const int SM_SHOWSOUNDS = 70;//如果用户要求应用程序在仅以声音形式显示信息的情况下直观显示信息,则为非零值;否则为 0。
public const int SM_CXMENUCHECK = 71;//默认菜单的宽度检查标记位图(以像素为单位)。
public const int SM_CYMENUCHECK = 72;//默认菜单的高度检查标记位图(以像素为单位)。
public const int SM_SLOWMACHINE = 73;//如果计算机具有低端 (慢) 处理器,则为非零值;否则为 0。
public const int SM_MIDEASTENABLED = 74;//如果为希伯来语和阿拉伯语启用系统,则为非零值;否则为 0。
public const int SM_MOUSEWHEELPRESENT = 75;//如果安装了具有垂直滚轮的鼠标,则为非零值;否则为 0。
public const int SM_XVIRTUALSCREEN = 76;//虚拟屏幕左侧的坐标。 虚拟屏幕是所有显示监视器的边框。 SM_CXVIRTUALSCREEN指标是虚拟屏幕的宽度。
public const int SM_YVIRTUALSCREEN = 77;//虚拟屏幕顶部的坐标。 虚拟屏幕是所有显示监视器的边框。 SM_CYVIRTUALSCREEN指标是虚拟屏幕的高度。
public const int SM_CXVIRTUALSCREEN = 78;//虚拟屏幕的宽度(以像素为单位)。 虚拟屏幕是所有显示监视器的边框。 SM_XVIRTUALSCREEN指标是虚拟屏幕左侧的坐标。
public const int SM_CYVIRTUALSCREEN = 79;//虚拟屏幕的高度(以像素为单位)。 虚拟屏幕是所有显示监视器的边框。 SM_YVIRTUALSCREEN指标是虚拟屏幕顶部的坐标。
public const int SM_CMONITORS = 80;//桌面上的显示监视器数。 有关详细信息,请参阅本主题中的“备注”部分。
public const int SM_SAMEDISPLAYFORMAT = 81;//如果所有显示监视器具有相同的颜色格式,则为非零值,否则为 0。 两个显示器可以具有相同的位深度,但颜色格式不同。 例如,红色、绿色和蓝色像素可以使用不同位数进行编码,或者这些位可以位于像素颜色值的不同位置。
public const int SM_IMMENABLED = 82;//如果启用了输入法管理器/输入法编辑器功能,则为非零值;否则为 0。 SM_IMMENABLED指示系统是否已准备好在 Unicode 应用程序上使用基于 Unicode 的 IME。
//若要确保依赖于语言的 IME 正常工作,检查 SM_DBCSENABLED和系统 ANSI 代码页。 否则,ANSI 到 Unicode 的转换可能无法正确执行,或者某些组件(如字体或注册表设置)可能不存在。
public const int SM_CXFOCUSBORDER = 83;//DrawFocusRect 绘制的焦点矩形的左边缘和右边缘的宽度。 此值以像素为单位。Windows 2000: 不支持此值。
public const int SM_CYFOCUSBORDER = 84;//DrawFocusRect 绘制的焦点矩形的上边缘和下边缘的高度。 此值以像素为单位。Windows 2000: 不支持此值。
public const int SM_TABLETPC = 86;//如果当前操作系统是 Windows XP 平板电脑版本,或者当前操作系统是 Windows Vista 或 Windows 7 并且平板电脑输入服务已启动,则为非零值;否则为 0。 SM_DIGITIZER设置指示运行 Windows 7 或 Windows Server 2008 R2 的设备支持的数字化器输入类型。 有关详细信息,请参阅“备注”。
public const int SM_MEDIACENTER = 87;//如果当前操作系统是 Windows XP,则为非零,Media Center Edition 为 0(如果不是)。
public const int SM_STARTER = 88;//如果当前操作系统为 Windows 7 简易版 Edition、Windows Vista 入门版 或 Windows XP Starter Edition,则为非零;否则为 0。
public const int SM_SERVERR2 = 89;//系统为 Windows Server 2003 R2 时的内部版本号;否则为 0。
public const int SM_MOUSEHORIZONTALWHEELPRESENT = 91;//如果安装了水平滚轮的鼠标,则为非零值;否则为 0。
public const int SM_CXPADDEDBORDER = 92;//带字幕窗口的边框填充量(以像素为单位)。Windows XP/2000: 不支持此值。
public const int SM_DIGITIZER = 94;//如果当前操作系统是 Windows 7 或 Windows Server 2008 R2 并且平板电脑输入服务已启动,则为非零;否则为 0。
//返回值是一个位掩码,用于指定设备支持的数字化器输入的类型。 有关详细信息,请参阅“备注”。
//Windows Server 2008、Windows Vista 和 Windows XP/2000: 不支持此值。
public const int SM_MAXIMUMTOUCHES = 95;//如果系统中存在数字化器,则为非零值;否则为 0。
//SM_MAXIMUMTOUCHES返回系统中每个数字化器支持的最大接触数的聚合最大值。 如果系统只有单点触控数字化器,则返回值为 1。 如果系统具有多点触控数字化器,则返回值是硬件可以提供的同时触点数。
//Windows Server 2008、Windows Vista 和 Windows XP/2000: 不支持此值。
public const int SM_REMOTESESSION = 0x1000;//此系统指标用于终端服务环境。 如果调用进程与终端服务客户端会话相关联,则返回值为非零值。 如果调用进程与终端服务控制台会话相关联,则返回值为 0。 Windows Server 2003 和 Windows XP: 控制台会话不一定是物理控制台。 有关详细信息,请参阅 WTSGetActiveConsoleSessionId。
public const int SM_SHUTTINGDOWN = 0x2000;//如果当前会话正在关闭,则为非零;否则为 0。Windows 2000: 不支持此值
public const int SM_REMOTECONTROL = 0x2001;//此系统指标在终端服务环境中用于确定是否远程控制当前终端服务器会话。 如果远程控制当前会话,则其值为非零值;否则为 0。
//可以使用终端服务管理工具(如终端服务管理器(tsadmin.msc) 和shadow.exe)来控制远程会话。 远程控制会话时,另一个用户可以查看该会话的内容,并可能与之交互。
public const int SM_CONVERTIBLESLATEMODE = 0x2003;//反映笔记本电脑或平板模式的状态,0 表示板模式,否则为非零。 当此系统指标发生更改时,系统会通过 LPARAM 中带有“ConvertibleSlateMode”
// 的WM_SETTINGCHANGE 发送广播消息。 请注意,此系统指标不适用于台式电脑。 在这种情况下,请使用 GetAutoRotationState。
public const int SM_SYSTEMDOCKED = 0x2004;//反映停靠模式的状态,0 表示未停靠模式,否则为非零。 当此系统指标发生更改时,系统会通过 LPARAM 中带有“SystemDockMode” 的WM_SETTINGCHANGE 发送广播消息。
[DllImport("user32")]
public static extern int GetSystemMetrics(int nIndex);
}
/// <summary>
/// 主显示器的分辨率和屏幕尺寸
/// </summary>
public class MonitorHelper
{
private const int HORZSIZE = 4;//以毫米为单位的显示宽度
private const int VERTSIZE = 6;//以毫米为单位的显示高度
private const int LOGPIXELSX = 88;//像素/逻辑英寸(水平)
private const int LOGPIXELSY = 90; //像素/逻辑英寸(垂直)
private const int DESKTOPVERTRES = 117;//垂直分辨率
private const int DESKTOPHORZRES = 118;//水平分辨率
/// <summary>
/// 获取DC句柄
/// </summary>
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hdc);
/// <summary>
/// 释放DC句柄
/// </summary>
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hdc);
/// <summary>
/// 获取句柄指定的数据
/// </summary>
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
/// <summary>
/// 获取分辨率
/// </summary>
/// <returns></returns>
public static Size GetResolutionRatio()
{
Size size = new Size();
IntPtr hdc = GetDC(IntPtr.Zero);
size.Width = GetDeviceCaps(hdc, DESKTOPHORZRES);
size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES);
ReleaseDC(IntPtr.Zero, hdc);
return size;
}
/// <summary>
/// 获取屏幕物理尺寸(mm,mm)
/// </summary>
/// <returns></returns>
public static Size GetScreenSize()
{
Size size = new Size();
IntPtr hdc = GetDC(IntPtr.Zero);
size.Width = GetDeviceCaps(hdc, HORZSIZE);
size.Height = GetDeviceCaps(hdc, VERTSIZE);
ReleaseDC(IntPtr.Zero, hdc);
return size;
}
/// <summary>
/// 获取屏幕(对角线)的尺寸---英寸
/// </summary>
/// <returns></returns>
public static float GetScreenInch()
{
Size size = GetScreenSize();
double inch = Math.Round(Math.Sqrt(Math.Pow(size.Width, 2) + Math.Pow(size.Height, 2)) / 25.4, 1);
return (float)inch;
}
}
#endregion
#region 鼠标结构体的dwFlags设置为MOUSEEVENTF_ABSOLUTE,将dx与dy移动量变成屏幕坐标,以像素为单位
public class MouseStructHelper
{
#region 获取鼠标屏幕坐标Window API,与Control.MousePosition功能一样
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out System.Drawing.Point lpPoint);
/// <summary>
/// 获取鼠标当前屏幕坐标
/// </summary>
public Point GetMousePosition()
{
Point mp = new Point();
if (GetCursorPos(out mp))
{
return mp;
}
else
{
return Point.Empty;
}
}
#endregion
/// <summary>
/// 当前鼠标坐标转换为鼠标结构体dx,dy
/// </summary>
/// <returns></returns>
public static Point MouseDxDy()
{
Point Mousedxdy = new Point();
Mousedxdy.X = Control.MousePosition.X * (65535 / SystemMetricsHelper.GetSystemMetrics(SystemMetricsHelper.SM_CXSCREEN));
Mousedxdy.Y = Control.MousePosition.Y * (65535 / SystemMetricsHelper.GetSystemMetrics(SystemMetricsHelper.SM_CYSCREEN));
return Mousedxdy;
}
/// <summary>
/// 指定鼠标屏幕坐标转换为鼠标结构体dx,dy
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static Point MouseDxDy(Point source)
{
Point Mousedxdy = new Point();
Mousedxdy.X = source.X * (65535 / SystemMetricsHelper.GetSystemMetrics(SystemMetricsHelper.SM_CXSCREEN));
Mousedxdy.Y = source.Y * (65535 / SystemMetricsHelper.GetSystemMetrics(SystemMetricsHelper.SM_CYSCREEN));
return Mousedxdy;
}
/// <summary>
/// 获取鼠标当前坐标到目的坐标之间的最短距离的坐标序列
/// </summary>
/// <param name="destination">目的点坐标</param>
/// <returns></returns>
public static List<Point> MovePoints(Point destination)
{
return MovePoints(destination, Control.MousePosition);
}
/// <summary>
/// 获取鼠标起始点到目的点之间最短距离的坐标序列。以两点之间X,Y方向长为主计算。
/// </summary>
/// <param name="destination">目的点坐标</param>
/// <param name="source">起始点坐标</param>
/// <returns></returns>
public static List<Point> MovePoints(Point destination, Point source)
{
List<Point> points = new List<Point>();
//原点与目标点一样
if (destination == source)
{
points.Add(destination);
return points;
}
else if (destination.X == source.X)//垂直移动
{
for (int i = 0; i <= Math.Abs(destination.Y - source.Y); i++)
{
Point tp = new Point();
tp.X = destination.X;
if (destination.Y < source.Y)
{
tp.Y = source.Y - i;
}
else
{
tp.Y = source.Y + i;
}
points.Add(tp);
}
return points;
}
else if (destination.Y == source.Y)//水平移动
{
for (int i = 0; i <= Math.Abs(destination.X - source.X); i++)
{
Point tp = new Point();
tp.Y = destination.Y;
if (destination.Y < source.Y)
{
tp.X = source.X - i;
}
else
{
tp.X = source.X + i;
}
points.Add(tp);
}
return points;
}
//原点与目标点不一样,并且非水平或非垂直移动,所有有斜率K
double K = Convert.ToDouble(Math.Abs(destination.Y - source.Y)) / Convert.ToDouble(Math.Abs(destination.X - source.X));
if (destination.Y > source.Y)//笛卡尔坐标系第一、二象限
{
if (destination.X > source.X)//笛卡尔坐标系第一象限
{
//向选择原点和目标点之间X和Y方向长边的一组移动
if ((destination.X - source.X) >= (destination.Y - source.Y))//X方向长
{
for (int i = 0; i <= (destination.X - source.X); i++)
{
Point tp = new Point();
tp.X = source.X + i;
tp.Y = source.Y + (int)(K * i);
points.Add(tp);
}
}
else//Y方向长
{
for (int i = 0; i <= (destination.Y - source.Y); i++)
{
Point tp = new Point();
tp.Y = source.Y + i;
tp.X = source.X + (int)(i / K);
points.Add(tp);
}
}
}
else//笛卡尔坐标系第二象限
{
//向选择原点和目标点之间X和Y方向长边的一组移动
if ((source.X - destination.X) >= (destination.Y - source.Y))//X方向长
{
for (int i = 0; i <= (source.X - destination.X); i++)
{
Point tp = new Point();
tp.X = source.X - i;
tp.Y = source.Y + (int)(K * i);
points.Add(tp);
}
}
else//Y方向长
{
for (int i = 0; i <= (destination.Y - source.Y); i++)
{
Point tp = new Point();
tp.Y = source.Y + i;
tp.X = source.X - (int)(i / K);
points.Add(tp);
}
}
}
}
else//笛卡尔坐标系第三、四象限
{
if (destination.X < source.X)//笛卡尔坐标系第三象限
{
//向选择原点和目标点之间X和Y方向长边的一组移动
if ((source.X - destination.X) >= (source.Y - destination.Y))//X方向长
{
for (int i = 0; i <= (source.X - destination.X); i++)
{
Point tp = new Point();
tp.X = source.X - i;
tp.Y = source.Y - (int)(K * i);
points.Add(tp);
}
}
else//Y方向长
{
for (int i = 0; i <= (source.Y - destination.Y); i++)
{
Point tp = new Point();
tp.Y = source.Y - i;
tp.X = source.X - (int)(i / K);
points.Add(tp);
}
}
}
else//笛卡尔坐标系第四象限
{
//向选择原点和目标点之间X和Y方向长边的一组移动
if ((destination.X - source.X) >= (source.Y - destination.Y))//X方向长
{
for (int i = 0; i <= (destination.X - source.X); i++)
{
Point tp = new Point();
tp.X = source.X + i;
tp.Y = source.Y - (int)(K * i);
points.Add(tp);
}
}
else//Y方向长
{
for (int i = 0; i <= (source.Y - destination.Y); i++)
{
Point tp = new Point();
tp.Y = source.Y - i;
tp.X = source.X + (int)(i / K);
points.Add(tp);
}
}
}
}
return points;
}
}
#endregion
#region 模拟鼠标键盘输入
public class SendKeyboardMouse
{
#region 虚拟键盘
/// <summary>
/// 虚拟按下键
/// </summary>
/// <param name="vkCode">键盘虚拟代码,可以从VKCODE类中取</param>
public void SendKeyDown(byte vkCode)
{
Input[] input = new Input[1];
input[0].type = InputType.KEYBOARD;
input[0].U.ki.wVk = vkCode;
input[0].U.ki.dwFlags = WindowsConstant.KEYEVENTF_KEYDOWN;
input[0].U.ki.time = NativeMethods.GetTickCount();
uint backNum = NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0]));
if (backNum < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟释放键
/// </summary>
/// <param name="vkCode">键盘虚拟代码,可以从VKCODE类中取</param>
public void SendKeyUp(byte vkCode)
{
Input[] input = new Input[1];
input[0].type = InputType.KEYBOARD;
input[0].U.ki.wVk = vkCode;
input[0].U.ki.dwFlags = WindowsConstant.KEYEVENTF_KEYUP;
input[0].U.ki.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟按下并释放键
/// </summary>
/// <param name="vkCode">键盘虚拟代码,可以从VKCODE类中取</param>
public void SendKeyPress(byte vkCode)
{
SendKeyDown(vkCode);
System.Threading.Thread.Sleep(200);
SendKeyUp(vkCode);
}
#endregion
#region 虚拟鼠标
/// <summary>
/// 虚拟鼠标滚轮滚动
/// </summary>
/// <param name="delta">正数表示向上滚动,负数表示向下滚动</param>
public void MouseWhell(int delta)
{
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.mouseData = delta;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_WHEEL;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟将鼠标光标直接移动到指定屏幕坐标处
/// </summary>
/// <param name="destination">目标处的屏幕坐标</param>
public void MouseMove(Point destination)
{
//将鼠标结构体dx,dy移动量转换为屏幕坐标
Point tp = MouseStructHelper.MouseDxDy(destination);
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dx = tp.X;
input[0].U.mi.dy = tp.Y;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_ABSOLUTE | WindowsConstant.MOUSEEVENTF_MOVE;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟有鼠标移动轨迹的鼠标移动,参数均是屏幕像素坐标
/// </summary>
/// <param name="destination">鼠标要移动到的目的点坐标</param>
/// <param name="source">鼠标移动的起点坐标,如果是鼠标当前坐标,用 Control.MousePosition</param>
/// <param name="lowSpeed">鼠标移动速度,数字越大越慢</param>
public void MouseMove(Point destination, Point source, uint lowSpeed = 200)
{
//计算鼠标起始点与目标点之间移动时最短距离的点序列
List<Point> movePoints = MouseStructHelper.MovePoints(destination, source);
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_ABSOLUTE | WindowsConstant.MOUSEEVENTF_MOVE;
for (int i = 0; i < movePoints.Count; i++)
{
Point tp = new Point();
tp = MouseStructHelper.MouseDxDy(movePoints[i]);
input[0].U.mi.dx = tp.X;
input[0].U.mi.dy = tp.Y;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
//以下这段循环,用于减缓鼠标移动速度,如果用Thread.Sleep(1),虽然只有1毫秒,也显得有点缓慢,大家可以根据自己需要选择使用。
int j = 0;
while (j < lowSpeed * 1000)
{
j++;
}
}
}
/// <summary>
/// 虚拟鼠标左键按下
/// </summary>
public void MouseLeftDown()
{
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_LEFTDOWN;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟鼠标右键按下
/// </summary>
public void MouseRightDown()
{
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_RIGHTDOWN;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟鼠标左键释放
/// </summary>
public void MouseLeftUp()
{
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_LEFTUP;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟鼠标右键释放
/// </summary>
public void MouseRightUp()
{
Input[] input = new Input[1];
input[0].type = InputType.MOUSE;
input[0].U.mi.dwFlags = WindowsConstant.MOUSEEVENTF_RIGHTUP;
input[0].U.mi.time = NativeMethods.GetTickCount();
if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>
/// 虚拟双击鼠标左键
/// </summary>
public void MouseLeftDBClick()
{
MouseLeftDown();
MouseLeftUp();
MouseLeftDown();
MouseLeftUp();
}
/// <summary>
/// 虚拟双击鼠标右键
/// </summary>
public void MouseRightDBClick()
{
MouseRightDown();
MouseRightUp();
MouseRightDown();
MouseRightUp();
}
#endregion
}
#endregion
}
SendKeyboardMouse m = new SendKeyboardMouse();
m.SendKeyPress((byte)'A');
一个使用C#操作Redis集群进行读写的详细例子
一个使用C#操作Redis集群进行读写的详细例子。这个例子将展示如何连接到Redis集群,以及如何执行基本的读写操作。
首先,确保你已经安装了StackExchange.Redis NuGet包。你可以在Visual Studio的NuGet包管理器中安装,或者使用以下命令:
Install-Package StackExchange.Redis
然后,你可以使用以下代码:
using StackExchange.Redis;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 配置Redis集群连接
ConfigurationOptions config = new ConfigurationOptions
{
EndPoints =
{
{ "localhost", 7000 },
{ "localhost", 7001 },
{ "localhost", 7002 }
// 添加所有集群节点
},
CommandMap = CommandMap.Create(new HashSet<string>
{
"SUBSCRIBE", "UNSUBSCRIBE", "CLUSTER"
}, available: false),
AllowAdmin = true
};
// 连接到Redis集群
using (ConnectionMultiplexer redis = await ConnectionMultiplexer.ConnectAsync(config))
{
// 获取数据库实例
IDatabase db = redis.GetDatabase();
// 写操作
Console.WriteLine("执行写操作...");
bool setResult = await db.StringSetAsync("mykey", "Hello, Redis Cluster!");
Console.WriteLine($"写入结果: {setResult}");
// 读操作
Console.WriteLine("\n执行读操作...");
string getValue = await db.StringGetAsync("mykey");
Console.WriteLine($"读取的值: {getValue}");
// 哈希表操作
Console.WriteLine("\n执行哈希表操作...");
await db.HashSetAsync("user:1", new HashEntry[]
{
new HashEntry("name", "John Doe"),
new HashEntry("email", "john@example.com"),
new HashEntry("age", "30")
});
HashEntry[] userInfo = await db.HashGetAllAsync("user:1");
Console.WriteLine("用户信息:");
foreach (var entry in userInfo)
{
Console.WriteLine($"{entry.Name}: {entry.Value}");
}
// 列表操作
Console.WriteLine("\n执行列表操作...");
await db.ListRightPushAsync("mylist", new RedisValue[] { "item1", "item2", "item3" });
long listLength = await db.ListLengthAsync("mylist");
Console.WriteLine($"列表长度: {listLength}");
RedisValue[] listItems = await db.ListRangeAsync("mylist");
Console.WriteLine("列表项:");
foreach (var item in listItems)
{
Console.WriteLine(item);
}
// 集合操作
Console.WriteLine("\n执行集合操作...");
await db.SetAddAsync("myset", new RedisValue[] { "member1", "member2", "member3" });
RedisValue[] setMembers = await db.SetMembersAsync("myset");
Console.WriteLine("集合成员:");
foreach (var member in setMembers)
{
Console.WriteLine(member);
}
}
}
}
这个例子展示了以下操作:
连接到Redis集群
字符串的读写操作
哈希表的操作
列表的操作
集合的操作
注意事项:
确保将连接配置中的EndPoints替换为你实际的Redis集群节点地址和端口。
这个例子使用了异步方法(Async后缀的方法)来提高性能。在实际应用中,这是推荐的做法。
使用using语句来确保ConnectionMultiplexer在不再需要时被正确释放。
在生产环境中,你应该添加适当的错误处理和重试逻辑,以处理网络问题或节点故障。
ConnectionMultiplexer是设计为长期重用的。在实际应用中,你通常会在应用程序启动时创建一个实例,并在整个应用程序生命周期中重用它。
这个例子展示了基本操作。Redis还支持更多高级特性,如发布/订阅、事务、Lua脚本等,你可以根据需要探索这些功能。
通过这个例子,你应该能够开始使用C#操作Redis集群了。随着你的应用需求的增长,你可以进一步探索StackExchange.Redis库提供的更多功能。
上一篇:MyCat使用技术收集
下一篇:asp.net网站之状态服务