您现在的位置是:网站首页> C#技术

C#经验总结

摘要

C#经验总结

C#常用API大全

TransactionScope支持其他数据库

C# 脚本引擎 CS-Script

C# 关于打印 - PrintRaw

打印底层驱动包

Word控件Spire.Doc 将 Word 转换为 PDF

C#调用C++ DLL

C#双面打印解决方法(打印word\excel\图片

.net 开源模板引擎jntemplate 教程

C#嵌入x86汇编——一个GPIO接口的实现

C#与VC相互调用之VC调用C#的DLL库

比较对象是否是一个(String内容相同是一个对象)

C# async 函数

C#中通过Process运行程序如何获取进程的标准输出

C#Post接口时如何忽略掉SSL证书验证或者添加ssl证书

VS2013打不开nuget

c# URL Protocol 调用 给winform exe传参数

WebClient HttpWebRequest等访问https站点SSL错误处理

关于C#的反射 Assembly.Load这个通过字节流加载dll,如何解决dll所依赖的dll问题

C#热键的使用

C#模拟发送全局热键的代码

C#模拟鼠标点击

一个完整的键盘鼠标模拟封装

一个使用C#操作Redis集群进行读写的详细例子


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];



};


//点击查看在C#中定义

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];



        };


//点击查看C++中定义

[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++;

                    };


.net 开源模板引擎jntemplate 教程

打开Jntemplate开发文档

数据在渲染前提供给引擎,不要在页面生成新的对象,不要修改页面模型数据,以免出现不可预的错误

赋值标签

语法:$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

    }

}

1.png


C#与VC相互调用之VC调用C#的DLL库

点击查看原文

在之前的博文 C#与VC相互调用之C#调用VC的DLL https://blog.csdn.net/xinxin_2011/article/details/86704660 里面讲了C#程序如何调用VC的DLL,这里我们来介绍VC程序调用C#的DLL。

项目创建

打开VS2010,因为涉及到两个程序,这里先创建一个空的解决方案:

1.png

然后往里面添加一个C#的DLL项目:

1.png

选择“类库”项目模板:

1.png

点击完成后生成如下文件:

1.png

默认生成的是Class1类,我们改名为“CSharpDll”,并添加如下代码:

1.png

接下来再创建一个VC项目,来测试DLL的调用:

1.png

这里创建一个基于对话框的MFC程序:

1.png

点击下一步,只选一个粗框架就可以了:

1.png

继续下一步,只勾选“公共控件清单”即可:

1.png

按照默认的名字生成类文件:

1.png

点击完成后,自动生成如下项目文件:

1.png


编写测试代码

简单修改下VC页面视图:

1.png

其中“调用C#的库”按钮ID为ID_CSHARPDLL_BTN,编辑框的ID为IDC_EDIT_RES。双击按钮,添加处理函数:

1.png

上面代码会有很多划红线的错误,因为用到了gcnew和System::String等公共语言运行库,所以得在项目属性中添加“公共语言运行时支持”:

1.png

此外注意文件上方要添加C#库的引用:


#using "../CSharpLibrary/bin/Debug/CSharpLibrary.dll"


using namespace CSharpLibrary;


这里注意路径的写法,默认当前路径是TestCSharpDll目录,而CSharpLibrary与TestCSharpDll同在一个解决方案目录中,生成的库在CSharpLibrary的bin/Debug目录下,所以这样写。

先别着急编译,因为VC程序要调用DLL必须保证生成的exe和dll文件在同一目录,所以需要改一下VC程序生成exe的路径:

1.png

写好后把把VC程序设置为启动项目:

1.png

设置好之后就可以编译了,成功后生成如下文件:

1.png

看到exe和dll都生成了就可以运行程序进行测试了:

1.png

可以看到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) 


好了,既然有这样的构造函数,我们就可以替代强制转换了,改为如下代码:

1.png

VC调用C#的DLL显示界面

上面只是介绍了简单的字符串传递,那么VC能不能调用C#的Dll中的界面呢?下面来测试一下,在CSharpLibrary项目中添加一个界面类:

1.png

然后编辑窗体视图如下:

1.png

然后修改CSharpDll类,添加调用界面的函数:

1.png

最后在VC的OnBnClickedCsharpdllBtn函数中添加调用的代码:

1.png

看一下运行的结果:

1.png

OK,一切正常。


比较对象是否是一个

Object.ReferenceEquals()方法用于确定指定的Object实例是否为同一实例。此方法不能被覆盖。因此,如果用户要测试两个对象引用是否相等,并且不确定是否要执行Equals方法,则可以调用ReferenceEquals方法。


用法: public static bool Object.ReferenceEquals (object ob1, object ob2);



C# 常用API函数大全

常用Windows API


1. API之网络函数

WNetAddConnection 创建同一个网络资源的永久性连接
WNetAddConnection2 创建同一个网络资源的连接
WNetAddConnection3 创建同一个网络资源的连接
WNetCancelConnection 结束一个网络连接
WNetCancelConnection2 结束一个网络连接
WNetCloseEnum 结束一次枚举操作
WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接
WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接
WNetEnumResource 枚举网络资源
WNetGetConnection 获取本地或已连接的一个资源的网络名称
WNetGetLastError 获取网络错误的扩展错误信息
WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称
WNetGetUser 获取一个网络资源用以连接的名字
WNetOpenEnum 启动对网络资源进行枚举的过程

2. API之消息函数

BroadcastSystemMessage 将一条系统消息广播给系统中所有的顶级窗口
GetMessagePos 取得消息队列中上一条消息处理完毕时的鼠标指针屏幕位置
GetMessageTime 取得消息队列中上一条消息处理完毕时的时间
PostMessage 将一条消息投递到指定窗口的消息队列
PostThreadMessage 将一条消息投递给应用程序
RegisterWindowMessage 获取分配给一个字串标识符的消息编号
ReplyMessage 答复一个消息
SendMessage 调用一个窗口的窗口函数,将一条消息发给那个窗口
SendMessageCallback 将一条消息发给窗口
SendMessageTimeout 向窗口发送一条消息
SendNotifyMessage 向窗口发送一条消息

3. API之文件处理函数

CloseHandle 关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等
CompareFileTime 对比两个文件的时间
CopyFile 复制文件
CreateDirectory 创建一个新目录
CreateFile 打开和创建文件、管道、邮槽、通信服务、设备以及控制台
CreateFileMapping 创建一个新的文件映射对象
DeleteFile 删除指定文件
DeviceIoControl 对设备执行指定的操作
DosDateTimeToFileTime 将DOS日期和时间值转换成一个 win32 FILETIME 值
FileTimeToDosDateTime 将一个 win32 FILETIME 值转换成DOS日期和时间值
FileTimeToLocalFileTime 将一个FILETIME结构转换成本地时间
FileTimeToSystemTime 根据一个FILETIME结构的内容,装载一个SYSTEMTIME结构
FindClose 关闭由FindFirstFile函数创建的一个搜索句柄
FindFirstFile 根据文件名查找文件
FindNextFile 根据调用FindFirstFile函数时指定的一个文件名查找下一个文件
FlushFileBuffers 针对指定的文件句柄,刷新内部文件缓冲区
FlushViewOfFile 将写入文件映射缓冲区的所有数据都刷新到磁盘
GetBinaryType 判断文件是否可以执行
GetCompressedFileSize 判断一个压缩文件在磁盘上实际占据的字节数
GetCurrentDirectory 在一个缓冲区中装载当前目录
GetDiskFreeSpace 获取与一个磁盘的组织有关的信息,以及了解剩余空间的容量
GetDiskFreeSpaceEx 获取与一个磁盘的组织以及剩余空间容量有关的信息
GetDriveType 判断一个磁盘驱动器的类型
GetExpandedName 取得一个压缩文件的全名
GetFileAttributes 判断指定文件的属性
GetFileInformationByHandle 这个函数提供了获取文件信息的一种机制
GetFileSize 判断文件长度
GetFileTime 取得指定文件的时间信息
GetFileType 在给出文件句柄的前提下,判断文件类型
GetFileVersionInfo 从支持版本标记的一个模块里获取文件版本信息
GetFileVersionInfoSize 针对包含了版本资源的一个文件,判断容纳文件版本信息需要一个多大的缓冲区
GetFullPathName 获取指定文件的完整路径名
GetLogicalDrives 判断系统中存在哪些逻辑驱动器字母
GetLogicalDriveStrings 获取一个字串,其中包含了当前所有逻辑驱动器的根驱动器路径
GetOverlappedResult 判断一个重叠操作当前的状态
GetPrivateProfileInt 为初始化文件(.ini文件)中指定的条目获取一个整数值
GetPrivateProfileSection 获取指定小节(在.ini文件中)所有项名和值的一个列表
GetPrivateProfileString 为初始化文件中指定的条目取得字串
GetProfileInt 取得win.ini初始化文件中指定条目的一个整数值
GetProfileSection 获取指定小节(在win.ini文件中)所有项名和值的一个列表
GetProfileString 为win.ini初始化文件中指定的条目取得字串
GetShortPathName 获取指定文件的短路径名
GetSystemDirectory 取得Windows系统目录(即System目录)的完整路径名
GetTempFileName 这个函数包含了一个临时文件的名字,它可由应用程序使用
GetTempPath 获取为临时文件指定的路径
GetVolumeInformation 获取与一个磁盘卷有关的信息
GetWindowsDirectory 获取Windows目录的完整路径名
hread 参考lread
hwrite 参考lwrite函数
lclose 关闭指定的文件
lcreat 创建一个文件
llseek 设置文件中进行读写的当前位置
LockFile 锁定文件的某一部分,使其不与其他应用程序共享
LockFileEx 与LockFile相似,只是它提供了更多的功能
lopen 以二进制模式打开指定的文件
lread 将文件中的数据读入内存缓冲区
lwrite 将数据从内存缓冲区写入一个文件
LZClose 关闭由LZOpenFile 或 LZInit函数打开的一个文件
LZCopy 复制一个文件
LZInit 这个函数用于初始化内部缓冲区
LZOpenFile 该函数能执行大量不同的文件处理,而且兼容于压缩文件
LZRead 将数据从文件读入内存缓冲区
LZSeek 设置一个文件中进行读写的当前位置
MapViewOfFile 将一个文件映射对象映射到当前应用程序的地址空间
MoveFile 移动文件
OpenFile 这个函数能执行大量不同的文件操作
OpenFileMapping 打开一个现成的文件映射对象
QueryDosDevice 在Windows NT中,DOS设备名会映射成NT系统设备名。该函数可判断当前的设备映射情况
ReadFile 从文件中读出数据
ReadFileEx 与ReadFile相似,只是它只能用于异步读操作,并包含了一个完整的回调
RegCloseKey 关闭系统注册表中的一个项(或键)
RegConnectRegistry 访问远程系统的部分注册表
RegCreateKey 在指定的项下创建或打开一个项
RegCreateKeyEx 在指定项下创建新项的更复杂的方式。在Win32环境中建议使用这个函数
RegDeleteKey 删除现有项下方一个指定的子项
RegDeleteValue 删除指定项下方的一个值
RegEnumKey 枚举指定项的子项。在Win32环境中应使用RegEnumKeyEx
RegEnumKeyEx 枚举指定项下方的子项
RegEnumValue 枚举指定项的值
RegFlushKey 将对项和它的子项作出的改动实际写入磁盘
RegGetKeySecurity 获取与一个注册表项有关的安全信息
RegLoadKey 从以前用RegSaveKey函数创建的一个文件里装载注册表信息
RegNotifyChangeKeyValue 注册表项或它的任何一个子项发生变化时,用这个函数提供一种通知机制
RegOpenKey 打开一个现有的注册表项
RegOpenKeyEx 打开一个现有的项。在win32下推荐使用这个函数
RegQueryInfoKey 获取与一个项有关的信息
RegQueryValue 取得指定项或子项的默认(未命名)值
RegQueryValueEx 获取一个项的设置值
RegReplaceKey 用一个磁盘文件保存的信息替换注册表信息;并创建一个备份,在其中包含当前注册表信息
RegRestoreKey 从一个磁盘文件恢复注册表信息
RegSaveKey 将一个项以及它的所有子项都保存到一个磁盘文件
RegSetKeySecurity 设置指定项的安全特性
RegSetValue 设置指定项或子项的默认值
RegSetValueEx 设置指定项的值
RegUnLoadKey 卸载指定的项以及它的所有子项
RemoveDirectory 删除指定目录
SearchPath 查找指定文件
SetCurrentDirectory 设置当前目录
SetEndOfFile 针对一个打开的文件,将当前文件位置设为文件末尾
SetFileAttributes 设置文件属性
SetFilePointer 在一个文件中设置当前的读写位置
SetFileTime 设置文件的创建、访问及上次修改时间
SetHandleCount 这个函数不必在win32下使用;即使使用,也不会有任何效果
SetVolumeLabel 设置一个磁盘的卷标(Label)
SystemTimeToFileTime 根据一个FILETIME结构的内容,载入一个SYSTEMTIME结构
UnlockFile 解除对一个文件的锁定
UnlockFileEx 解除对一个文件的锁定
UnmapViewOfFile 在当前应用程序的内存地址空间解除对一个文件映射对象的映射
VerFindFile 用这个函数决定一个文件应安装到哪里
VerInstallFile 用这个函数安装一个文件
VerLanguageName 这个函数能根据16位语言代码获取一种语言的名称
VerQueryValue 这个函数用于从版本资源中获取信息
WriteFile 将数据写入一个文件
WriteFileEx 与WriteFile类似,只是它只能用于异步写操作,并包括了一个完整的回调
WritePrivateProfileSection 为一个初始化文件(.ini)中指定的小节设置所有项名和值
WritePrivateProfileString 在初始化文件指定小节内设置一个字串
WriteProfileSection 为Win.ini初始化文件中一个指定的小节设置所有项名和值
WriteProfileString 在Win.ini初始化文件指定小节内设置一个字串

4. API之打印函数

AbortDoc 取消一份文档的打印
AbortPrinter 删除与一台打印机关联在一起的缓冲文件
AddForm 为打印机的表单列表添加一个新表单
AddJob 用于获取一个有效的路径名,以便用它为作业创建一个后台打印文件。它也会为作业分配一个作业编号
AddMonitor 为系统添加一个打印机监视器
AddPort 启动“添加端口”对话框,允许用户在系统可用端口列表中加入一个新端口
AddPrinter 在系统中添加一台新打印机
AddPrinterConnection 连接指定的打印机
AddPrinterDriver 为指定的系统添加一个打印驱动程序
AddPrintProcessor 为指定的系统添加一个打印处理器
AddPrintProvidor 为系统添加一个打印供应商
AdvancedDocumentProperties 启动打印机文档设置对话框
ClosePrinter 关闭一个打开的打印机对象
ConfigurePort 针对指定的端口,启动一个端口配置对话框
ConnectToPrinterDlg 启动连接打印机对话框,用它同访问网络的打印机连接
DeleteForm 从打印机可用表单列表中删除一个表单
DeleteMonitor 删除指定的打印监视器
DeletePort 启动“删除端口”对话框,允许用户从当前系统删除一个端口
DeletePrinter 将指定的打印机标志为从系统中删除
DeletePrinterConnection 删除与指定打印机的连接
DeletePrinterDriver 从系统删除一个打印机驱动程序
DeletePrintProcessor 从指定系统删除一个打印处理器
DeletePrintProvidor 从系统中删除一个打印供应商
DeviceCapabilities 利用这个函数可获得与一个设备的能力有关的信息
DocumentProperties 打印机配置控制函数
EndDocAPI 结束一个成功的打印作业
EndDocPrinter 在后台打印程序的级别指定一个文档的结束
EndPage 用这个函数完成一个页面的打印,并准备设备场景,以便打印下一个页
EndPagePrinter 指定一个页在打印作业中的结尾
EnumForms 枚举一台打印机可用的表单
EnumJobs 枚举打印队列中的作业
EnumMonitors 枚举可用的打印监视器
EnumPorts 枚举一个系统可用的端口
EnumPrinterDrivers 枚举指定系统中已安装的打印机驱动程序
EnumPrinters 枚举系统中安装的打印机
EnumPrintProcessorDatatypes 枚举由一个打印处理器支持的数据类型
EnumPrintProcessors 枚举系统中可用的打印处理器
Escape 设备控制函数
FindClosePrinterChangeNotification 关闭用FindFirstPrinterChangeNotification函数获取的一个打印机通告对象
FindFirstPrinterChangeNotification 创建一个新的改变通告对象,以便我们注意打印机状态的各种变化
FindNextPrinterChangeNotification 用这个函数判断触发一次打印机改变通告信号的原因
FreePrinterNotifyInfo 释放由FindNextPrinterChangeNotification函数分配的一个缓冲区
GetForm 取得与指定表单有关的信息
GetJob 获取与指定作业有关的信息
GetPrinter 取得与指定打印机有关的信息
GetPrinterData 为打印机设置注册表配置信息
GetPrinterDriver 针对指定的打印机,获取与打印机驱动程序有关的信息
GetPrinterDriverDirectory 判断指定系统中包含了打印机驱动程序的目录是什么
GetPrintProcessorDirectory 判断指定系统中包含了打印机处理器驱动程序及文件的目录
OpenPrinter 打开指定的打印机,并获取打印机的句柄
PrinterMessageBox 在拥有指定打印作业的系统上显示一个打印机出错消息框
PrinterProperties 启动打印机属性对话框,以便对打印机进行配置
ReadPrinter 从打印机读入数据
ResetDC 重设一个设备场景
ResetPrinter 改变指定打印机的默认数据类型及文档设置
ScheduleJob 提交一个要打印的作业
SetAbortProc 为Windows指定取消函数的地址
SetForm 为指定的表单设置信息
SetJob 对一个打印作业的状态进行控制
SetPrinter 对一台打印机的状态进行控制
SetPrinterData 设置打印机的注册表配置信息
StartDoc 开始一个打印作业
StartDocPrinter 在后台打印的级别启动一个新文档
StartPage 打印一个新页前要先调用这个函数
StartPagePrinter 在打印作业中指定一个新页的开始
WritePrinter 将发送目录中的数据写入打印机

5. API之文本和字体函数

AddFontResource 在Windows系统中添加一种字体资源
CreateFont 用指定的属性创建一种逻辑字体
CreateFontIndirect 用指定的属性创建一种逻辑字体
CreateScalableFontResource 为一种TureType字体创建一个资源文件,以便能用API函数AddFontResource将其加入Windows系统
DrawText 将文本描绘到指定的矩形中
DrawTextEx 与DrawText相似,只是加入了更多的功能
EnumFontFamilies 列举指定设备可用的字体
EnumFontFamiliesEx 列举指定设备可用的字体
EnumFonts 列举指定设备可用的字体
ExtTextOut 经过扩展的文本描绘函数。也请参考SetTextAlign函数
GetAspectRatioFilterEx 用SetMapperFlags要求Windows只选择与设备当前纵横比相符的光栅字体时,本函数可判断纵横比大小
GetCharABCWidths 判断TureType字体中一个或多个字符的A-B-C大小
GetCharABCWidthsFloat 查询一种字体中一个或多个字符的A-B-C尺寸
GetCharacterPlacement 该函数用于了解如何用一个给定的字符显示一个字串
GetCharWidth 调查字体中一个或多个字符的宽度
GetFontData 接收一种可缩放字体文件的数据
GetFontLanguageInfo 返回目前选入指定设备场景中的字体的信息
GetGlyphOutline 取得TureType字体中构成一个字符的曲线信息
GetKerningPairs 取得指定字体的字距信息
GetOutlineTextMetrics 接收与TureType字体内部特征有关的详细信息
GetRasterizerCaps 了解系统是否有能力支持可缩放的字体
GetTabbedTextExtent 判断一个字串占据的范围,同时考虑制表站扩充的因素
GetTextAlign 接收一个设备场景当前的文本对齐标志
GetTextCharacterExtra 判断额外字符间距的当前值
GetTextCharset 接收当前选入指定设备场景的字体的字符集标识符
GetTextCharsetInfo 获取与当前选定字体的字符集有关的详细信息
GetTextColor 判断当前字体颜色。通常也称为“前景色”
GetTextExtentExPoint 判断要填入指定区域的字符数量。也用一个数组装载每个字符的范围信息
GetTextExtentPoint 判断一个字串的大小(范围)
GetTextFace 获取一种字体的字样名
GetTextMetrics 获取与选入一种设备场景的物理字体有关的信息
GrayString 描绘一个以灰色显示的字串。通常由Windows用于标识禁止状态
PolyTextOut 描绘一系列字串
RemoveFontResource 从Windows系统中删除一种字体资源
SetMapperFlags Windows对字体进行映射时,可用该函数选择与目标设备的纵横比相符的光栅字体
SetTextAlign 设置文本对齐方式,并指定在文本输出过程中使用设备场景的当前位置
SetTextCharacterExtra 描绘文本的时候,指定要在字符间插入的额外间距
SetTextColor 设置当前文本颜色。这种颜色也称为“前景色”
SetTextJustification 通过指定一个文本行应占据的额外空间,可用这个函数对文本进行两端对齐处理
TabbedTextOut 支持制表站的一个文本描绘函数
TextOut 文本绘图函数

6. API之菜单函数

AppendMenu 在指定的菜单里添加一个菜单项
CheckMenuItem 复选或撤消复选指定的菜单条目
CheckMenuRadioItem 指定一个菜单条目被复选成“单选”项目
CreateMenu 创建新菜单
CreatePopupMenu 创建一个空的弹出式菜单
DeleteMenu 删除指定的菜单条目
DestroyMenu 删除指定的菜单
DrawMenuBar 为指定的窗口重画菜单
EnableMenuItem 允许或禁止指定的菜单条目
GetMenu 取得窗口中一个菜单的句柄
GetMenuCheckMarkDimensions 返回一个菜单复选符的大小
GetMenuContextHelpId 取得一个菜单的帮助场景ID
GetMenuDefaultItem 判断菜单中的哪个条目是默认条目
GetMenuItemCount 返回菜单中条目(菜单项)的数量
GetMenuItemID 返回位于菜单中指定位置处的条目的菜单ID
GetMenuItemInfo 取得(接收)与一个菜单条目有关的特定信息
GetMenuItemRect 在一个矩形中装载指定菜单条目的屏幕坐标信息
GetMenuState 取得与指定菜单条目状态有关的信息
GetMenuString 取得指定菜单条目的字串
GetSubMenu 取得一个弹出式菜单的句柄,它位于菜单中指定的位置
GetSystemMenu 取得指定窗口的系统菜单的句柄
HiliteMenuItem 控制顶级菜单条目的加亮显示状态
InsertMenu 在菜单的指定位置处插入一个菜单条目,并根据需要将其他条目向下移动
InsertMenuItem 插入一个新菜单条目
IsMenu 判断指定的句柄是否为一个菜单的句柄
LoadMenu 从指定的模块或应用程序实例中载入一个菜单
LoadMenuIndirect 载入一个菜单
MenuItemFromPoint 判断哪个菜单条目包含了屏幕上一个指定的点
ModifyMenu 改变菜单条目
RemoveMenu 删除指定的菜单条目
SetMenu 设置窗口菜单
SetMenuContextHelpId 设置一个菜单的帮助场景ID
SetMenuDefaultItem 将一个菜单条目设为默认条目
SetMenuItemBitmaps 设置一幅特定位图,令其在指定的菜单条目中使用,代替标准的复选符号(√)
SetMenuItemInfo 为一个菜单条目设置指定的信息
TrackPopupMenu 在屏幕的任意地方显示一个弹出式菜单
TrackPopupMenuEx 与TrackPopupMenu相似,只是它提供了额外的功能

7. API之位图、图标和光栅运算函数

BitBlt 将一幅位图从一个设备场景复制到另一个
CopyIcon 制作指定图标或鼠标指针的一个副本。这个副本从属于发出调用的应用程序
CopyImage 复制位图、图标或指针,同时在复制过程中进行一些转换工作
CreateBitmap 按照规定的格式创建一幅与设备有关位图
CreateBitmapIndirect 创建一幅与设备有关位图
CreateCompatibleBitmap 创建一幅与设备有关位图,它与指定的设备场景兼容
CreateCursor 创建一个鼠标指针
CreateDIBitmap 根据一幅与设备无关的位图创建一幅与设备有关的位图
CreateDIBSection 创建一个DIBSection
CreateIcon 创建一个图标
CreateIconIndirect 创建一个图标
DestroyCursor 清除指定的鼠标指针,并释放它占用的所有系统资源
DestroyIcon 清除图标
DrawIcon 在指定的位置画一个图标
DrawIconEx 描绘一个图标或鼠标指针。与DrawIcon相比,这个函数提供了更多的功能
ExtractAssociatedIcon 判断一个可执行程序或DLL中是否存在图标,或是否有图标与系统注册表中指定的文件存在关联并提取之
ExtractIcon 判断一个可执行文件或DLL中是否有图标存在,并将其提取出来
GetBitmapBits 将来自位图的二进制位复制到一个缓冲区
GetBitmapDimensionEx 取得一幅位图的宽度和高度
GetDIBColorTable 从选入设备场景的DIBSection中取得颜色表信息
GetDIBits 将来自一幅位图的二进制位复制到一幅与设备无关的位图里
GetIconInfo 取得与图标有关的信息
GetStretchBltMode 判断StretchBlt 和 StretchDIBits函数采用的伸缩模式
LoadBitmap 从指定的模块或应用程序实例中载入一幅位图
LoadCursor 从指定的模块或应用程序实例中载入一个鼠标指针
LoadCursorFromFile 在一个指针文件或一个动画指针文件的基础上创建一个指针
LoadIcon 从指定的模块或应用程序实例中载入一个图标
LoadImage 载入一个位图、图标或指针
MaskBlt 执行复杂的图象传输,同时进行掩模(MASK)处理
PatBlt 在当前选定的刷子的基础上,用一个图案填充指定的设备场景
PlgBlt 复制一幅位图,同时将其转换成一个平行四边形。利用它可对位图进行旋转处理
SetBitmapBits 将来自缓冲区的二进制位复制到一幅位图
SetBitmapDimensionEx 设置一幅位图的宽度。以一毫米的十分之一为单位
SetDIBColorTable 设置选入设备场景的一个DIBSection的颜色表信息
SetDIBits 将来自与设备无关位图的二进制位复制到一幅与设备有关的位图里
SetDIBitsToDevice 将一幅与设备无关位图的全部或部分数据直接复制到一个设备
SetStretchBltMode 指定StretchBlt 和 StretchDIBits函数的伸缩模式
StretchBlt 将一幅位图从一个设备场景复制到另一个
StretchDIBits 将一幅与设备无关位图的全部或部分数据直接复制到指定的设备场景

8. API之绘图函数

AbortPath 抛弃选入指定设备场景中的所有路径。也取消目前正在进行的任何路径的创建工作
AngleArc 用一个连接弧画一条线
Arc 画一个圆弧
BeginPath 启动一个路径分支
CancelDC 取消另一个线程里的长时间绘图操作
Chord 画一个弦
CloseEnhMetaFile 关闭指定的增强型图元文件设备场景,并将新建的图元文件返回一个句柄
CloseFigure 描绘到一个路径时,关闭当前打开的图形
CloseMetaFile 关闭指定的图元文件设备场景,并向新建的图元文件返回一个句柄
CopyEnhMetaFile 制作指定增强型图元文件的一个副本(拷贝)
CopyMetaFile 制作指定(标准)图元文件的一个副本
CreateBrushIndirect 在一个LOGBRUSH数据结构的基础上创建一个刷子
CreateDIBPatternBrush 用一幅与设备无关的位图创建一个刷子,以便指定刷子样式(图案)
CreateEnhMetaFile 创建一个增强型的图元文件设备场景
CreateHatchBrush 创建带有阴影图案的一个刷子
CreateMetaFile 创建一个图元文件设备场景
CreatePatternBrush 用指定了刷子图案的一幅位图创建一个刷子
CreatePen 用指定的样式、宽度和颜色创建一个画笔
CreatePenIndirect 根据指定的LOGPEN结构创建一个画笔
CreateSolidBrush 用纯色创建一个刷子
DeleteEnhMetaFile 删除指定的增强型图元文件
DeleteMetaFile 删除指定的图元文件
DeleteObject 删除GDI对象,对象使用的所有系统资源都会被释放
DrawEdge 用指定的样式描绘一个矩形的边框
DrawEscape 换码(Escape)函数将数据直接发至显示设备驱动程序
DrawFocusRect 画一个焦点矩形
DrawFrameControl 描绘一个标准控件
DrawState 为一幅图象或绘图操作应用各式各样的效果
Ellipse 描绘一个椭圆,由指定的矩形围绕
EndPath 停止定义一个路径
EnumEnhMetaFile 针对一个增强型图元文件,列举其中单独的图元文件记录
EnumMetaFile 为一个标准的windows图元文件枚举单独的图元文件记录
EnumObjects 枚举可随同指定设备场景使用的画笔和刷子
ExtCreatePen 创建一个扩展画笔(装饰或几何)
ExtFloodFill 在指定的设备场景里,用当前选择的刷子填充一个区域
FillPath 关闭路径中任何打开的图形,并用当前刷子填充
FillRect 用指定的刷子填充一个矩形
FlattenPath 将一个路径中的所有曲线都转换成线段
FloodFill 用当前选定的刷子在指定的设备场景中填充一个区域
FrameRect 用指定的刷子围绕一个矩形画一个边框
GdiComment 为指定的增强型图元文件设备场景添加一条注释信息
GdiFlush 执行任何未决的绘图操作
GdiGetBatchLimit 判断有多少个GDI绘图命令位于队列中
GdiSetBatchLimit 指定有多少个GDI绘图命令能够进入队列
GetArcDirection 画圆弧的时候,判断当前采用的绘图方向
GetBkColor 取得指定设备场景当前的背景颜色
GetBkMode 针对指定的设备场景,取得当前的背景填充模式
GetBrushOrgEx 判断指定设备场景中当前选定刷子起点
GetCurrentObject 获得指定类型的当前选定对象
GetCurrentPositionEx 在指定的设备场景中取得当前的画笔位置
GetEnhMetaFile 取得磁盘文件中包含的一个增强型图元文件的图元文件句柄
GetEnhMetaFileBits 将指定的增强型图元文件复制到一个内存缓冲区里
GetEnhMetaFileDescription 返回对一个增强型图元文件的说明
GetEnhMetaFileHeader 取得增强型图元文件的图元文件头
GetEnhMetaFilePaletteEntries 取得增强型图元文件的全部或部分调色板
GetMetaFile 取得包含在一个磁盘文件中的图元文件的图元文件句柄
GetMetaFileBitsEx 将指定的图元文件复制到一个内存缓冲区
GetMiterLimit 取得设备场景的斜率限制(Miter)设置
GetNearestColor 根据设备的显示能力,取得与指定颜色最接近的一种纯色
GetObjectAPI 取得对指定对象进行说明的一个结构
GetObjectType 判断由指定句柄引用的GDI对象的类型
GetPath 取得对当前路径进行定义的一系列数据
GetPixel 在指定的设备场景中取得一个像素的RGB值
GetPolyFillMode 针对指定的设备场景,获得多边形填充模式
GetROP2 针对指定的设备场景,取得当前的绘图模式
GetStockObject 取得一个固有对象(Stock)
GetSysColorBrush 为任何一种标准系统颜色取得一个刷子
GetWinMetaFileBits 通过在一个缓冲区中填充用于标准图元文件的数据,将一个增强型图元文件转换成标准windows图元文件
InvertRect 通过反转每个像素的值,从而反转一个设备场景中指定的矩形
LineDDA 枚举指定线段中的所有点
LineTo 用当前画笔画一条线,从当前位置连到一个指定的点
MoveToEx 为指定的设备场景指定一个新的当前画笔位置
PaintDesk 在指定的设备场景中描绘桌面墙纸图案
PathToRegion 将当前选定的路径转换到一个区域里
Pie 画一个饼图
PlayEnhMetaFile 在指定的设备场景中画一个增强型图元文件
PlayEnhMetaFileRecord 回放单独一条增强型图元文件记录
PlayMetaFile 在指定的设备场景中回放一个图元文件
PlayMetaFileRecord 回放来自图元文件的单条记录
PolyBezier 描绘一条或多条贝塞尔(Bezier)曲线
PolyDraw 描绘一条复杂的曲线,由线段及贝塞尔曲线组成
Polygon 描绘一个多边形
Polyline 用当前画笔描绘一系列线段
PolyPolygon 用当前选定画笔描绘两个或多个多边形
PolyPolyline 用当前选定画笔描绘两个或多个多边形
Rectangle 用当前选定的画笔描绘矩形,并用当前选定的刷子填充
RoundRect 用当前选定的画笔画一个圆角矩形,并用当前选定的刷子在其中填充
SelectClipPath 将设备场景当前的路径合并到剪切区域里
SelectObject 为当前设备场景选择图形对象
SetArcDirection 设置圆弧的描绘方向
SetBkColor 为指定的设备场景设置背景颜色
SetBkMode 指定阴影刷子、虚线画笔以及字符中的空隙的填充方式
SetBrushOrgEx 为指定的设备场景设置当前选定刷子的起点
SetEnhMetaFileBits 用指定内存缓冲区内包含的数据创建一个增强型图元文件
SetMetaFileBitsEx 用包含在指定内存缓冲区内的数据结构创建一个图元文件
SetMiterLimit 设置设备场景当前的斜率限制
SetPixel 在指定的设备场景中设置一个像素的RGB值
SetPixelV 在指定的设备场景中设置一个像素的RGB值
SetPolyFillMode 设置多边形的填充模式
SetROP2 设置指定设备场景的绘图模式。与vb的DrawMode属性完全一致
SetWinMetaFileBits 将一个标准Windows图元文件转换成增强型图元文件
StrokeAndFillPath 针对指定的设备场景,关闭路径上打开的所有区域
StrokePath 用当前画笔描绘一个路径的轮廓。打开的图形不会被这个函数关闭
UnrealizeObject 将一个刷子对象选入设备场景之前,如刷子的起点准备用SetBrushOrgEx修改,则必须先调用本函数
WidenPath 根据选定画笔的宽度,重新定义当前选定的路径

9. API之设备场景函数

CombineRgn 将两个区域组合为一个新区域
CombineTransform 驱动世界转换。它相当于依顺序进行两次转换
CreateCompatibleDC 创建一个与特定设备场景一致的内存设备场景
CreateDC 为专门设备创建设备场景
CreateEllipticRgn 创建一个椭圆
CreateEllipticRgnIndirect 创建一个内切于特定矩形的椭圆区域
CreateIC 为专用设备创建一个信息场景
CreatePolygonRgn 创建一个由一系列点围成的区域
CreatePolyPolygonRgn 创建由多个多边形构成的区域。每个多边形都应是封闭的
CreateRectRgn 创建一个矩形区域
CreateRectRgnIndirect 创建一个矩形区域
CreateRoundRectRgn 创建一个圆角矩形
DeleteDC 删除专用设备场景或信息场景,释放所有相关窗口资源
DPtoLP 将点阵从设备坐标转换到专用设备场景逻辑坐标
EqualRgn 确定两个区域是否相等
ExcludeClipRect 从专用设备场景的剪裁区中去掉一个矩形区。矩形内不能进行绘图
ExcludeUpdateRgn 从专用设备场景剪裁区去掉指定窗口的刷新区域
ExtCreateRegion 根据世界转换修改区域
ExtSelectClipRgn 将指定区域组合到设备场景的当前剪裁区
FillRgn 用指定刷子填充指定区域
FrameRgn 用指定刷子围绕指定区域画一个外框
GetBoundsRect 获取指定设备场景的边界矩形
GetClipBox 获取完全包含指定设备场景剪裁区的最小矩形
GetClipRgn 获取设备场景当前剪裁区
GetDC 获取指定窗口的设备场景
GetDCEx 为指定窗口获取设备场景。相比GetDC,本函数提供了更多的选项
GetDCOrgEx 获取指定设备场景起点位置(以屏幕坐标表示)
GetDeviceCaps 根据指定设备场景代表的设备的功能返回信息
GetGraphicsMode 确定是否允许增强图形模式(世界转换)
GetMapMode 为特定设备场景调入映象模式
GetRegionData 装入描述一个区域信息的RgnData结构或缓冲区
GetRgnBox 获取完全包含指定区域的最小矩形
GetUpdateRgn 确定指定窗口的刷新区域。该区域当前无效,需要刷新
GetViewportExtEx 获取设备场景视口(viewport)范围
GetViewportOrgEx 获取设备场景视口起点
GetWindowDC 获取整个窗口(包括边框、滚动条、标题栏、菜单等)的设备场景
GetWindowExtEx 获取指定设备场景的窗口范围
GetWindowOrgEx 获取指定设备场景的逻辑窗口的起点
GetWindowRgn 获取窗口区域
GetWorldTransform 如果有世界转换,为设备场景获取当前世界转换
IntersectClipRect 为指定设备定义一个新的剪裁区
InvalidateRgn 使窗口指定区域不活动,并将它加入窗口刷新区,使之可随后被重画
InvertRgn 通过颠倒每个像素值反转设备场景指定区域
LPtoDP 将点阵从指定设备场景逻辑坐标转换为设备坐标
ModifyWorldTransform 根据指定的模式修改世界转换
OffsetClipRgn 按指定量平移设备场景剪裁区
OffsetRgn 按指定偏移量平移指定区域
OffsetViewportOrgEx 平移设备场景视口区域
OffsetWindowOrgEx 平移指定设备场景窗口起点
PaintRgn 用当前刷子背景色填充指定区域
PtInRegion 确定点是否在指定区域内
PtVisible 确定指定点是否可见(即,点是否在设备场景剪裁区内)
RectInRegion 确定矩形是否有部分在指定区域内
RectVisible 确定指定矩形是否有部分可见(是否在设备场景剪裁区内)
ReleaseDC 释放由调用GetDC或GetWindowDC函数获取的指定设备场景
RestoreDC 从设备场景堆栈恢复一个原先保存的设备场景
SaveDC 将指定设备场景状态保存到Windows设备场景堆栈
ScaleViewportExtEx 缩放设备场景视口的范围
ScaleWindowExtEx 缩放指定设备场景窗口范围
ScrollDC 在窗口(由设备场景代表)中水平和(或)垂直滚动矩形
SelectClipRgn 为指定设备场景选择新的剪裁区
SetBoundsRect 设置指定设备场景的边界矩形
SetGraphicsMode 允许或禁止增强图形模式,以提供某些支持(包括世界转换)
SetMapMode 设置指定设备场景的映射模式
SetRectRgn 设置区域为指定的矩形
SetViewportExtEx 设置设备场景视口范围
SetViewportOrgEx 设置设备场景视口起点
SetWindowExtEx 设置指定设备场景窗口范围
SetWindowOrgEx 设置指定设备场景窗口起点
SetWindowRgn 设置窗口区域
SetWorldTransform 设置世界转换
ValidateRgn 激活窗口中指定区域,把它从刷新区移走
WindowFromDC 取回与某一设备场景相关的窗口的句柄

10. API之硬件与系统函数

ActivateKeyboardLayout 激活一个新的键盘布局。键盘布局定义了按键在一种物理性键盘上的位置与含义
Beep 用于生成简单的声音
CharToOem 将一个字串从ANSI字符集转换到OEM字符集
ClipCursor 将指针限制到指定区域
ConvertDefaultLocale 将一个特殊的地方标识符转换成真实的地方ID
CreateCaret 根据指定的信息创建一个插入符(光标),并将它选定为指定窗口的默认插入符
DestroyCaret 清除(破坏)一个插入符
EnumCalendarInfo 枚举在指定“地方”环境中可用的日历信息
EnumDateFormats 列举指定的“当地”设置中可用的长、短日期格式
EnumSystemCodePages 枚举系统中已安装或支持的代码页
EnumSystemLocales 枚举系统已经安装或提供支持的“地方”设置
EnumTimeFormats 枚举一个指定的地方适用的时间格式
ExitWindowsEx 退出windows,并用特定的选项重新启动
ExpandEnvironmentStrings 扩充环境字串
FreeEnvironmentStrings 翻译指定的环境字串块
GetACP 判断目前正在生效的ANSI代码页
GetAsyncKeyState 判断函数调用时指定虚拟键的状态
GetCaretBlinkTime 判断插入符光标的闪烁频率
GetCaretPos 判断插入符的当前位置
GetClipCursor 取得一个矩形,用于描述目前为鼠标指针规定的剪切区域
GetCommandLine 获得指向当前命令行缓冲区的一个指针
GetComputerName 取得这台计算机的名称
GetCPInfo 取得与指定代码页有关的信息
GetCurrencyFormat 针对指定的“地方”设置,根据货币格式格式化一个数字
GetCursor 获取目前选择的鼠标指针的句柄
GetCursorPos 获取鼠标指针的当前位置
GetDateFormat 针对指定的“当地”格式,对一个系统日期进行格式化
GetDoubleClickTime 判断连续两次鼠标单击之间会被处理成双击事件的间隔时间
GetEnvironmentStrings 为包含了当前环境字串设置的一个内存块分配和返回一个句柄
GetEnvironmentVariable 取得一个环境变量的值
GetInputState 判断是否存在任何待决(等待处理)的鼠标或键盘事件
GetKBCodePage 由GetOEMCP取代,两者功能完全相同
GetKeyboardLayout 取得一个句柄,描述指定应用程序的键盘布局
GetKeyboardLayoutList 获得系统适用的所有键盘布局的一个列表
GetKeyboardLayoutName 取得当前活动键盘布局的名称
GetKeyboardState 取得键盘上每个虚拟键当前的状态
GetKeyboardType 了解与正在使用的键盘有关的信息
GetKeyNameText 在给出扫描码的前提下,判断键名
GetKeyState 针对已处理过的按键,在最近一次输入信息时,判断指定虚拟键的状态
GetLastError 针对之前调用的api函数,用这个函数取得扩展错误信息
GetLocaleInfo 取得与指定“地方”有关的信息
GetLocalTime 取得本地日期和时间
GetNumberFormat 针对指定的“地方”,按特定的格式格式化一个数字
GetOEMCP 判断在OEM和ANSI字符集间转换的windows代码页
GetQueueStatus 判断应用程序消息队列中待决(等待处理)的消息类型
GetSysColor 判断指定windows显示对象的颜色
GetSystemDefaultLangID 取得系统的默认语言ID
GetSystemDefaultLCID 取得当前的默认系统“地方”
GetSystemInfo 取得与底层硬件平台有关的信息
GetSystemMetrics 返回与windows环境有关的信息
GetSystemPowerStatus 获得与当前系统电源状态有关的信息
GetSystemTime 取得当前系统时间,这个时间采用的是“协同世界时间”(即UTC,也叫做GMT)格式
GetSystemTimeAdjustment 使内部系统时钟与一个外部的时钟信号源同步
GetThreadLocale 取得当前线程的地方ID
GetTickCount 用于获取自windows启动以来经历的时间长度(毫秒)
GetTimeFormat 针对当前指定的“地方”,按特定的格式格式化一个系统时间
GetTimeZoneInformation 取得与系统时区设置有关的信息
GetUserDefaultLangID 为当前用户取得默认语言ID
GetUserDefaultLCID 取得当前用户的默认“地方”设置
GetUserName 取得当前用户的名字
GetVersion 判断当前运行的Windows和DOS版本
GetVersionEx 取得与平台和操作系统有关的版本信息
HideCaret 在指定的窗口隐藏插入符(光标)
IsValidCodePage 判断一个代码页是否有效
IsValidLocale 判断地方标识符是否有效
keybd_event 这个函数模拟了键盘行动
LoadKeyboardLayout 载入一个键盘布局
MapVirtualKey 根据指定的映射类型,执行不同的扫描码和字符转换
MapVirtualKeyEx 根据指定的映射类型,执行不同的扫描码和字符转换
MessageBeep 播放一个系统声音。系统声音的分配方案是在控制面板里决定的
mouse_event 模拟一次鼠标事件
OemKeyScan 判断OEM字符集中的一个ASCII字符的扫描码和Shift键状态
OemToChar 将OEM字符集的一个字串转换到ANSI字符集
SetCaretBlinkTime 指定插入符(光标)的闪烁频率
SetCaretPos 指定插入符的位置
SetComputerName 设置新的计算机名
SetCursor 将指定的鼠标指针设为当前指针
SetCursorPos 设置指针的位置
SetDoubleClickTime 设置连续两次鼠标单击之间能使系统认为是双击事件的间隔时间
SetEnvironmentVariable 将一个环境变量设为指定的值
SetKeyboardState 设置每个虚拟键当前在键盘上的状态
SetLocaleInfo 改变用户“地方”设置信息
SetLocalTime 设置当前地方时间
SetSysColors 设置指定窗口显示对象的颜色
SetSystemCursor 改变任何一个标准系统指针
SetSystemTime 设置当前系统时间
SetSystemTimeAdjustment 定时添加一个校准值使内部系统时钟与一个外部的时钟信号源同步
SetThreadLocale 为当前线程设置地方
SetTimeZoneInformation 设置系统时区信息
ShowCaret 在指定的窗口里显示插入符(光标)
ShowCursor 控制鼠标指针的可视性
SwapMouseButton 决定是否互换鼠标左右键的功能
SystemParametersInfo 获取和设置数量众多的windows系统参数
SystemTimeToTzSpecificLocalTime 将系统时间转换成地方时间
ToAscii 根据当前的扫描码和键盘信息,将一个虚拟键转换成ASCII字符
ToUnicode 根据当前的扫描码和键盘信息,将一个虚拟键转换成Unicode字符
UnloadKeyboardLayout 卸载指定的键盘布局
VkKeyScan 针对Windows字符集中一个ASCII字符,判断虚拟键码和Shift键的状态

11. API之进程和线程函数

CancelWaitableTimer 这个函数用于取消一个可以等待下去的计时器操作
CallNamedPipe 这个函数由一个希望通过管道通信的一个客户进程调用
ConnectNamedPipe 指示一台服务器等待下去,直至客户机同一个命名管道连接
CreateEvent 创建一个事件对象
CreateMailslot 创建一个邮路。返回的句柄由邮路服务器使用(收件人)
CreateMutex 创建一个互斥体(MUTEX)
CreateNamedPipe 创建一个命名管道。返回的句柄由管道的服务器端使用
CreatePipe 创建一个匿名管道
CreateProcess 创建一个新进程(比如执行一个程序)
CreateSemaphore 创建一个新的信号机
CreateWaitableTimer 创建一个可等待的计时器对象
DisconnectNamedPipe 断开一个客户与一个命名管道的连接
DuplicateHandle 在指出一个现有系统对象当前句柄的情况下,为那个对象创建一个新句柄
ExitProcess 中止一个进程
FindCloseChangeNotification 关闭一个改动通知对象
FindExecutable 查找与一个指定文件关联在一起的程序的文件名
FindFirstChangeNotification 创建一个文件通知对象。该对象用于监视文件系统发生的变化
FindNextChangeNotification 重设一个文件改变通知对象,令其继续监视下一次变化
FreeLibrary 释放指定的动态链接库
GetCurrentProcess 获取当前进程的一个伪句柄
GetCurrentProcessId 获取当前进程一个唯一的标识符
GetCurrentThread 获取当前线程的一个伪句柄
GetCurrentThreadId 获取当前线程一个唯一的线程标识符
GetExitCodeProces 获取一个已中断进程的退出代码
GetExitCodeThread 获取一个已中止线程的退出代码
GetHandleInformation 获取与一个系统对象句柄有关的信息
GetMailslotInfo 获取与一个邮路有关的信息
GetModuleFileName 获取一个已装载模板的完整路径名称
GetModuleHandle 获取一个应用程序或动态链接库的模块句柄
GetPriorityClass 获取特定进程的优先级别
GetProcessShutdownParameters 调查系统关闭时一个指定的进程相对于其它进程的关闭早迟情况
GetProcessTimes 获取与一个进程的经过时间有关的信息
GetProcessWorkingSetSize 了解一个应用程序在运行过程中实际向它交付了多大容量的内存
GetSartupInfo 获取一个进程的启动信息
GetThreadPriority 获取特定线程的优先级别
GetTheardTimes 获取与一个线程的经过时间有关的信息
GetWindowThreadProcessId 获取与指定窗口关联在一起的一个进程和线程标识符
LoadLibrary 载入指定的动态链接库,并将它映射到当前进程使用的地址空间
LoadLibraryEx 装载指定的动态链接库,并为当前进程把它映射到地址空间
LoadModule 载入一个Windows应用程序,并在指定的环境中运行
MsgWaitForMultipleObjects 等侯单个对象或一系列对象发出信号。如返回条件已经满足,则立即返回
SetPriorityClass 设置一个进程的优先级别
SetProcessShutdownParameters 在系统关闭期间,为指定进程设置他相对于其它程序的关闭顺序
SetProcessWorkingSetSize 设置操作系统实际划分给进程使用的内存容量
SetThreadPriority 设定线程的优先级别
ShellExecute 查找与指定文件关联在一起的程序的文件名
TerminateProcess 结束一个进程
WinExec 运行指定的程序

12. API之控件与消息函数

AdjustWindowRect 给定一种窗口样式,计算获得目标客户区矩形所需的窗口大小
AnyPopup 判断屏幕上是否存在任何弹出式窗口
ArrangeIconicWindows 排列一个父窗口的最小化子窗口
AttachThreadInput 连接线程输入函数
BeginDeferWindowPos 启动构建一系列新窗口位置的过程
BringWindowToTop 将指定的窗口带至窗口列表顶部
CascadeWindows 以层叠方式排列窗口
ChildWindowFromPoint 返回父窗口中包含了指定点的第一个子窗口的句柄
ClientToScreen 判断窗口内以客户区坐标表示的一个点的屏幕坐标
CloseWindow 最小化指定的窗口
CopyRect 矩形内容复制
DeferWindowPos 该函数为特定的窗口指定一个新窗口位置
DestroyWindow 清除指定的窗口以及它的所有子窗口
DrawAnimatedRects 描绘一系列动态矩形
EnableWindow 指定的窗口里允许或禁止所有鼠标及键盘输入
EndDeferWindowPos 同时更新DeferWindowPos调用时指定的所有窗口的位置及状态
EnumChildWindows 为指定的父窗口枚举子窗口
EnumThreadWindows 枚举与指定任务相关的窗口
EnumWindows 枚举窗口列表中的所有父窗口
EqualRect 判断两个矩形结构是否相同
FindWindow 寻找窗口列表中第一个符合指定条件的顶级窗口
FindWindowEx 在窗口列表中寻找与指定条件相符的第一个子窗口
FlashWindow 闪烁显示指定窗口
GetActiveWindow 获得活动窗口的句柄
GetCapture 获得一个窗口的句柄,这个窗口位于当前输入线程,且拥有鼠标捕获(鼠标活动由它接收)
GetClassInfo 取得WNDCLASS结构(或WNDCLASSEX结构)的一个副本,结构中包含了与指定类有关的信息
GetClassLong 取得窗口类的一个Long变量条目
GetClassName 为指定的窗口取得类名
GetClassWord 为窗口类取得一个整数变量
GetClientRect 返回指定窗口客户区矩形的大小
GetDesktopWindow 获得代表整个屏幕的一个窗口(桌面窗口)句柄
GetFocus 获得拥有输入焦点的窗口的句柄
GetForegroundWindow 获得前台窗口的句柄
GetLastActivePopup 获得在一个给定父窗口中最近激活过的弹出式窗口的句柄
GetParent 判断指定窗口的父窗口
GetTopWindow 搜索内部窗口列表,寻找隶属于指定窗口的头一个窗口的句柄
GetUpdateRect 获得一个矩形,它描叙了指定窗口中需要更新的那一部分
GetWindow 获得一个窗口的句柄,该窗口与某源窗口有特定的关系
GetWindowContextHelpId 取得与窗口关联在一起的帮助场景ID
GetWindowLong 从指定窗口的结构中取得信息
GetWindowPlacement 获得指定窗口的状态及位置信息
GetWindowRect 获得整个窗口的范围矩形,窗口的边框、标题栏、滚动条及菜单等都在这个矩形内
GetWindowText 取得一个窗体的标题(caption)文字,或者一个控件的内容
GetWindowTextLength 调查窗口标题文字或控件内容的长短
GetWindowWord 获得指定窗口结构的信息
InflateRect 增大或减小一个矩形的大小
IntersectRect 这个函数在lpDestRect里载入一个矩形,它是lpSrc1Rect与lpSrc2Rect两个矩形的交集
InvalidateRect 屏蔽一个窗口客户区的全部或部分区域
IsChild 判断一个窗口是否为另一窗口的子或隶属窗口
IsIconic 判断窗口是否已最小化
IsRectEmpty 判断一个矩形是否为空
IsWindow 判断一个窗口句柄是否有效
IsWindowEnabled 判断窗口是否处于活动状态
IsWindowUnicode 判断一个窗口是否为Unicode窗口。这意味着窗口为所有基于文本的消息都接收Unicode文字
IsWindowVisible 判断窗口是否可见
IsZoomed 判断窗口是否最大化
LockWindowUpdate 锁定指定窗口,禁止它更新
MapWindowPoints 将一个窗口客户区坐标的点转换到另一窗口的客户区坐标系统
MoveWindow 改变指定窗口的位置和大小
OffsetRect 通过应用一个指定的偏移,从而让矩形移动起来
OpenIcon 恢复一个最小化的程序,并将其激活
PtInRect 判断指定的点是否位于矩形内部
RedrawWindow 重画全部或部分窗口
ReleaseCapture 为当前的应用程序释放鼠标捕获
ScreenToClient 判断屏幕上一个指定点的客户区坐标
ScrollWindow 滚动窗口客户区的全部或一部分
ScrollWindowEx 根据附加的选项,滚动窗口客户区的全部或部分
SetActiveWindow 激活指定的窗口
SetCapture 将鼠标捕获设置到指定的窗口
SetClassLong 为窗口类设置一个Long变量条目
SetClassWord 为窗口类设置一个条目
SetFocusAPI 将输入焦点设到指定的窗口。如有必要,会激活窗口
SetForegroundWindow 将窗口设为系统的前台窗口
SetParent 指定一个窗口的新父
SetRect 设置指定矩形的内容
SetRectEmpty 将矩形设为一个空矩形
SetWindowContextHelpId 为指定的窗口设置帮助场景(上下文)ID
SetWindowLong 在窗口结构中为指定的窗口设置信息
SetWindowPlacement 设置窗口状态和位置信息
SetWindowPos 为窗口指定一个新位置和状态
SetWindowText 设置窗口的标题文字或控件的内容
SetWindowWord 在窗口结构中为指定的窗口设置信息
ShowOwnedPopups 显示或隐藏由指定窗口所有的全部弹出式窗口
ShowWindow 控制窗口的可见性
ShowWindowAsync 与ShowWindow相似
SubtractRect 装载矩形lprcDst,它是在矩形lprcSrc1中减去lprcSrc2得到的结果
TileWindows 以平铺顺序排列窗口
UnionRect 装载一个lpDestRect目标矩形,它是lpSrc1Rect和lpSrc2Rect联合起来的结果
UpdateWindow 强制立即更新窗口
ValidateRect 校验窗口的全部或部分客户区
WindowFromPoint 返回包含了指定点的窗口的句柄。忽略屏蔽、隐藏以及透明窗口
WNetAddConnection 创建同一个网络资源的永久性连接
WNetAddConnection2 创建同一个网络资源的连接
WNetAddConnection3 创建同一个网络资源的连接
WNetCancelConnection 结束一个网络连接
WNetCancelConnection2 结束一个网络连接
WNetCloseEnum 结束一次枚举操作
WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接
WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接
WNetEnumResource 枚举网络资源
WNetGetConnection 获取本地或已连接的一个资源的网络名称
WNetGetLastError 获取网络错误的扩展错误信息
WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC(统一命名规范)名称
WNetGetUser 获取一个网络资源用以连接的名字
WNetOpenEnum 启动对网络资源进行枚举的过程


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集群进行读写的详细例子

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库提供的更多功能。































Top