2004年08月30日

                                                                                                                 
    1、基本语法
   
    C#是一个块结构语言,所有的语句都是代码块的一部分。这些块用花括号来界定(“{”“}”),可以包含任意多行语句,或者根本不包含语句。
   
    {
     <code line1, statement 1>;
     <code line2, statement 2>
      <code line3, statement 3>;
    }
   
    其中<code line X, statement Y>部分并不是真正的C#代码,而是用这个文本作为占位符。
   
    注释语句:
     /* And so ……
     
     …… is this!*/
     
    或者
   
    //This is a different sort of comment.
   
    2、变量
   
    C#声明变量的语法:
    <type> <name>;
   
    变量类型:
    sbyte byte short ushort int uint long ulong float double decimal char bool string
   
    3、变量的命名
   
    变量名的第一个字符必须是字母、下划线或@。
    其后的字符可以是字母、下划线或者数字。
   
    4、名称空间
   
        他们是.net中提供应用程序代码容器的方式,这样,代码及其内容就可以唯一地标识了。名称空间也是用作.NET Framework 中给项目分类的一种方式。
    在默认的情况下,C#代码包含在全局命名空间中。可以使用namespace关键字为花括号中的代码块显示定义名称空间。如果在该名称空间代码的外部使
    用名称空间中的名称,就必须写出该名称空间的限定名称。
      基本上如果一个名称空间的代码需要使用的另一个名称空间中定义的名称,就必须包含对该名称空间的引用。限定名称在不同的名称空间级别之间使用
    字符”.”。
   
    例如:
   
     namespace LevelOne
     
     {
      //code
     }
     
    这段代码定义了一个名称空间LevelOne。
   

2004年08月22日

 

 

 

 

  许多软件都有自动关机功能,特别是在长时间下载的时候,这个功能可是使你不用以守候在计算机前面,而电脑却能按照您事先的设定自动关闭。现在我们用visual C#来编写一个多功能的关机程序。该程序具有:定时关机、倒计时关机、关机提醒、系统信息获取等四项功能, 可设定关机时间精确到秒。并且让你很快掌握Visual C#中对API的操作程序。


  一. 设计关闭Windows窗体

  1. 界面的设计

  新建一个标准工程,向工程中增加一个Windows窗体并向窗体中添加如下控件,并分别设置其属性:

控件名 类别 Text 控件名 类别 Text
CheckBox1 CheckBox 自动关机 GroupBox1 GroupBox 当前系统时间
CheckBox1 CheckBox 倒计时执行操作 GroupBox2 GroupBox 设定时间
CheckBox1 CheckBox 定时报警 TxtTime TextBox  
ButCancle Button 取消 SetupTime DateTimePicker  
ButReOpen Button 重新启动 SetupDate DateTimePicker  
ButClose Button 关机 Timer1 Timer 100
ButSysInto Button 系统信息 ButReLogin Button 注消

  Windows窗体界面:

  将窗体属性中的caption设置为”关闭windows”,名称设置为”frmmain”。

  2. 在窗体类中引用API函数

  API函数是构筑Windows应用程序的基石,是Windows编程的必备利器。每一种Windows应用程序开发工具都提供了间接或直接调用了Windows API函数的方法,或者是调用Windows API函数的接口,也就是说具备调用动态连接库的能力。Visual C#和其它开发工具一样也能够调用动态链接库的API函数。

  在Visual C#中调用API的基本过程:

  首先,在调用API之前,你必须先导入System.Runtime.InteropServices这个名称空间。该名称空间包含了在Visual C#中调用API的一些必要集合,具体的方法如下:

  using System.Runtime.InteropServices ;
  using System.Text ;

  在导入了名称空间后,我们要声明在程序中所要用到的API函数。我们的程序主要是获取系统的相关信息,所以用到的API函数都是返回系统信息的。先给出在Visual C#中声明API的方法:

[ DllImport("user32") ]
public static extern long SetWindowPos(long hwnd , long hWndInsertAfter, long X , long y , long cx, long cy, long wFlagslong) ;

  其中,”DllImport”属性用来从不可控代码中调用一个方法,它指定了DLL的位置,该DLL中包含调用的外部方法;”kernel32″设定了类库名;”public”指明函数的访问类型为公有的;”static”修饰符声明一个静态元素,而该元素属于类型本身而不是指定的对象;”extern”表示该方法将在工程外部执行,同时使用DllImport导入的方法必须使用”extern”修饰符;最后GetWindowsDirectory函数包含了两个参数,一个为StringBuilder类型的,另一个为int类型的,该方法返回的内容存在于StringBuilder类型的参数中。同时,因为我们在这里使用到了StringBuilder类,所以在程序的开始处,我们还得添加System.Text这个名称空间,方法同上。

  声明其它的在程序中所要用到的API函数:

[ DllImport("user32") ]
public static extern long ExitWindowsEx(long uFlags, long dwReserved ) ;
[ DllImport("shell32") ]
public static extern long ShellAbout(long uFlags, long dwReserved ) ;

  3. 增加窗体类的变量

long dwReserved ;
const int SHUTDOWN = 1 ;
const int REBOOT = 2 ;
const int LOGOFF = 0 ;
long sh ;
int counter , n ;

  4. 编写窗体类的方法

  在窗体的Load(事件过程中编写如下代码:

private void frmmain1_Load(object sender, System.EventArgs e )
{
file://用系统时间初始化组件
Time.Text = System.DateTime.Today.ToShortDateString( ) + ” “+ System.DateTime.Today.ToLongTimeString( ) ;
}

  在组件Timer1的OnTimer事件过程中编写如下代码:

/ / 在组件Timer1的OnTimer事件过程中编写如下代码:
private void Timer1_Timer(object sender, System.EventArgs e )
{
file://接收当前日期和时间,用于即时显示
string CurrDate=System.DateTime.Today.ToShortDateString( ) ;
string CurrTime=System.DateTime.Today.ToShortTimeString( ) ;
file://随时检测设定的关机日期和时间是否有效
if( this.CheckBox1.Checked == true )
{
if(CurrDate== SetupDate.ToString( ) && CurrTime==SetupTime.ToString( ) )
ColseComputer( ) ;
}
}
private void ColseComputer( )
{ sh = ExitWindowsEx(SHUTDOWN, dwReserved) ; }
private void button1_Click(object sender, System.EventArgs e )
{
Form2 frm=new Form2( ) ;
frm.Show( ) ;
}
private void ButReOpen_Click(object sender, System.EventArgs e )
{ sh = ExitWindowsEx(REBOOT, dwReserved) ; }
private void ButReLogin_Click(object sender, System.EventArgs e )
{ sh = ExitWindowsEx(LOGOFF, dwReserved) ; }
private void ButCancle_Click(object sender, System.EventArgs e )
{ this.Close( ) ; }
private void ButClose_Click_1(object sender, System.EventArgs e )
{ sh = ExitWindowsEx(REBOOT, dwReserved) ; }

  二. 设计获取系统信息的Windows窗体

  1. 界面的设计

  向工程中增加一个Windows窗体并向窗体中添加如下控件:

  2. 在窗体类中引用API函数

using System.Runtime.InteropServices ;
using System.Text ;
[ DllImport("kernel32") ]
public static extern void GetWindowsDirectory(StringBuilder WinDir,int count) ;
[ DllImport("kernel32") ]
public static extern void GetSystemDirectory(StringBuilder SysDir,int count) ;
[ DllImport("kernel32") ]
public static extern void GetSystemInfo(ref CPU_INFO cpuinfo) ;
[ DllImport("kernel32") ]
public static extern void GlobalMemoryStatus(ref MEMORY_INFO meminfo) ;
[ DllImport("kernel32") ]
public static extern void GetSystemTime(ref SYSTEMTIME_INFO stinfo) ;

  以上几个API的作用分别是获取系统路径,获得CPU相关信息,获得内存的相关信息,获得系统时间等。

  3. 定义以下各结构

  在声明完所有的API函数后,我们发现后三个函数分别用到了CPU_INFO、MEMORY_INFO、SYSTEMTIME_INFO等结构,这些结构并非是.Net内部的,它们从何而来?其实,我们在用到以上API调用时均需用到以上结构,我们将函数调用获得的信息存放在以上的结构体中,最后返回给程序输出。这些结构体比较复杂,但是如果开发者能够熟练运用,那么整个API世界将尽在开发者的掌握之中。以下就是上述结构体的声明:

//定义CPU的信息结构
[StructLayout(LayoutKind.Sequential) ]
public struct CPU_INFO
{
public uint dwOemId ;
public uint dwPageSize ;
public uint lpMinimumApplicationAddress ;
public uint lpMaximumApplicationAddress ;
public uint dwActiveProcessorMask ;
public uint dwNumberOfProcessors ;
public uint dwProcessorType ;
public uint dwAllocationGranularity ;
public uint dwProcessorLevel ;
public uint dwProcessorRevision ;
}

file://定义内存的信息结构
[StructLayout(LayoutKind.Sequential) ]
public struct MEMORY_INFO
{
public uint dwLength ;
public uint dwMemoryLoad ;
public uint dwTotalPhys ;
public uint dwAvailPhys ;
public uint dwTotalPageFile ;
public uint dwAvailPageFile ;
public uint dwTotalVirtual ;
public uint dwAvailVirtual ;
}

file://定义系统时间的信息结构
[StructLayout(LayoutKind.Sequential) ]
public struct SYSTEMTIME_INFO
{
public ushort wYear ;
public ushort wMonth ;
public ushort wDayOfWeek ;
public ushort wDay ;
public ushort wHour ;
public ushort wMinute ;
public ushort wSecond ;
public ushort wMilliseconds ;
}

  5. 编写窗体类的方法

private void button1_Click(object sender, System.EventArgs e )
{
file://调用GetWindowsDirectory和GetSystemDirectory函数分别取得Windows路径和系统路径
const int nChars = 128 ;
StringBuilder Buff = new StringBuilder(nChars) ;
GetWindowsDirectory(Buff,nChars) ;
WindowsDirectory.Text = “Windows路径:”+Buff.ToString( ) ;
GetSystemDirectory(Buff,nChars) ;
SystemDirectory.Text = ” 系统路径:”+Buff.ToString( ) ;

file://调用GetSystemInfo函数获取CPU的相关信息
CPU_INFO CpuInfo ;
CpuInfo = new CPU_INFO( ) ;
GetSystemInfo(ref CpuInfo) ;
NumberOfProcessors.Text = “本计算机中有”+CpuInfo.dwNumberOfProcessors.ToString( ) +”个CPU”;
ProcessorType.Text = “CPU的类型为”+CpuInfo.dwProcessorType.ToString( ) ;
ProcessorLevel.Text = “CPU等级为”+CpuInfo.dwProcessorLevel.ToString( ) ;
OemId.Text = “CPU的OEM ID为”+CpuInfo.dwOemId.ToString( ) ;
PageSize.Text = “CPU中的页面大小为”+CpuInfo.dwPageSize.ToString( ) ;

file://调用GlobalMemoryStatus函数获取内存的相关信息
MEMORY_INFO MemInfo ;
MemInfo = new MEMORY_INFO( ) ;
GlobalMemoryStatus(ref MemInfo) ;
MemoryLoad.Text = MemInfo.dwMemoryLoad.ToString( ) +”%的内存正在使用” ;
TotalPhys.Text = “物理内存共有”+MemInfo.dwTotalPhys.ToString( ) +”字节” ;
AvailPhys.Text = “可使用的物理内存有”+MemInfo.dwAvailPhys.ToString( ) +”字节” ;
TotalPageFile.Text = “交换文件总大小为”+MemInfo.dwTotalPageFile.ToString( ) +”字节” ;
AvailPageFile.Text = “尚可交换文件大小为”+MemInfo.dwAvailPageFile.ToString( ) +”字节” ;
TotalVirtual.Text = “总虚拟内存有”+MemInfo.dwTotalVirtual.ToString( ) +”字节” ;
AvailVirtual.Text = “未用虚拟内存有”+MemInfo.dwAvailVirtual.ToString( ) +”字节” ;

file://调用GetSystemTime函数获取系统时间信息
SYSTEMTIME_INFO StInfo ;
StInfo = new SYSTEMTIME_INFO( ) ;
GetSystemTime(ref StInfo) ;
Date.Text = StInfo.wYear.ToString( ) +”年”+StInfo.wMonth.ToString( ) +”月”+StInfo.wDay.ToString( ) +”日” ;
Time.Text = (StInfo.wHour+8).ToString( ) +”点”+StInfo.wMinute.ToString( ) +”分”+StInfo.wSecond.ToString( ) +”秒” ;
}

  三. 结束语。

  上面介绍了Visual C#开发多功能关机程序的整个过程,该程序有一定的实用价值。通过本文的学习,我相信稍有API使用基础的开发者可以马上触类旁通,很快掌握Visual C#中对API的操作。上面给出的实例仅仅是一个简单的程序,不过有兴趣的读者可以进一步完善其功能,做出更完美的系统应用程序。

首先建立两个C#应用程序项目。

  第一个项目包含一个Windows Form(Form1),在Form1上有一个Button和一个TextBox。

  第二个项目包含一个Windows Form(Form1),在Form1上有两个Button,分别用来测试第一个应用程序中Button的Click事件和修改第一个应用程序中TextBox的值。

  第一个应用程序中Form的代码如下:




  using System;
  using System.Drawing;
  using System.Collections;
  using System.ComponentModel;
  using System.Windows.Forms;

  public class Form1 : System.Windows.Forms.Form {
  private System.Windows.Forms.Button button1;
  private System.Windows.Forms.TextBox textBox1;

  private System.ComponentModel.Container components = null;

  [STAThread]
  static void Main() {
  Application.Run(new Form1());
  }

  public Form1()
  {
  InitializeComponent();
  }
  protected override void Dispose( bool disposing )
  {
  if( disposing )
  {
  if(components != null)
  {
  components.Dispose();
  }
  }
  base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  private void InitializeComponent()
  {
  this.button1 = new System.Windows.Forms.Button();
  this.textBox1 = new System.Windows.Forms.TextBox();
  this.SuspendLayout();
  //

  // button1
  //
  this.button1.Location = new System.Drawing.Point(32, 24);
  this.button1.Name = “button1″;
  this.button1.TabIndex = 0;
  this.button1.Text = “button1″;
  this.button1.Click += new System.EventHandler(this.button1_Click);
  //
  // textBox1
  //
  this.textBox1.Location = new System.Drawing.Point(32, 64);
  this.textBox1.Name = “textBox1″;
  this.textBox1.TabIndex = 1;
  this.textBox1.Text = “textBox1″;
  //
  // Form1
  //
  this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
  this.ClientSize = new System.Drawing.Size(292, 266);
  this.Controls.Add(this.textBox1);
  this.Controls.Add(this.button1);
  this.Name = “Form1″;
  this.Text = “Form1″; 
  this.ResumeLayout(false);

  }
  #endregion

  private void button1_Click(object sender, System.EventArgs e) {
  MessageBox.Show(“This is button1 click!”);
  }
  }

  第二个应用程序中Form的代码如下:

  using System;
  using System.Text;
  using System.Drawing;
  using System.Collections;
  using System.ComponentModel;
  using System.Windows.Forms;
  using System.Runtime.InteropServices;

  public class TestForm1 : System.Windows.Forms.Form {
  private System.Windows.Forms.Button button1;
  private System.Windows.Forms.Button button2;

  private System.ComponentModel.Container components = null;

 

  [STAThread]
  static void Main() {
  Application.Run(new TestForm1());
  }

  public TestForm1()
  {
  InitializeComponent();
  }
  protected override void Dispose( bool disposing )
  {
  if( disposing )
  {
  if(components != null)
  {
  components.Dispose();
  }
  }
  base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  private void InitializeComponent()
  {
  this.button1 = new System.Windows.Forms.Button();
  this.button2 = new System.Windows.Forms.Button();
  this.SuspendLayout();
  //
  // button1
  //
  this.button1.Location = new System.Drawing.Point(32, 24);
  this.button1.Name = “button1″;
  this.button1.TabIndex = 0;
  this.button1.Text = “button1″;
  this.button1.Click += new System.EventHandler(this.button1_Click);
  //
  // button2
  //
  this.button2.Location = new System.Drawing.Point(32, 64);
  this.button2.Name = “button2″;
  this.button2.TabIndex = 0;
  this.button2.Text = “button2″;
  this.button2.Click += new System.EventHandler(this.button2_Click);
  //
  // TestForm1
  //
  this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
  this.ClientSize = new System.Drawing.Size(292, 266);


  this.Controls.Add(this.button1);
  this.Controls.Add(this.button2); 
  this.Name = “TestForm1″;
  this.Text = “TestForm1″; 
  this.ResumeLayout(false);

  }
  #endregion

  private void button1_Click(object sender, System.EventArgs e) {
  IntPtr hwnd_win ;  
  IntPtr hwnd_button ;

  hwnd_win = FindWindow(“WindowsForms10.Window.8.app3″,”Form1″);
  hwnd_button = FindWindowEx(hwnd_win ,new IntPtr(0) ,”WindowsForms10.BUTTON.app3″,”button1″); 

  const int BM_CLICK = 0×00F5;
  Message msg = Message.Create(hwnd_button ,BM_CLICK ,new IntPtr(0),new IntPtr(0));
  PostMessage(msg.HWnd ,msg.Msg ,msg.WParam ,msg.LParam);
  }
  private void button2_Click(object sender, System.EventArgs e) {
  const int WM_CHAR = 0×0102;
  IntPtr hwnd_win ;
  IntPtr hwnd_textbox ;

  hwnd_win = FindWindow(“WindowsForms10.Window.8.app3″,”Form1″);  
  hwnd_textbox = FindWindowEx(hwnd_win ,new IntPtr(0) ,”WindowsForms10.EDIT.app3″,”textBox1″);    
  
  string strtext = “测试aaa”;
  UnicodeEncoding encode = new UnicodeEncoding();
  char[] chars = encode.GetChars(encode.GetBytes(strtext));
  Message msg ;
  foreach (char c in chars ) {
  msg = Message.Create(hwnd_textbox ,WM_CHAR ,new IntPtr(c),new IntPtr(0));
  PostMessage(msg.HWnd ,msg.Msg ,msg.WParam ,msg.LParam);
  }
  }

  [DllImport("user32.dll")]
  public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  
  [DllImport("user32.dll")]
  public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter,string lpszClass,string lpszWindow);

  [DllImport("user32.dll",CharSet=CharSet.Unicode)] 
  public static extern IntPtr PostMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);
  }

  以上代码可以在VS.NET中编译运行,也可以使用csc.exe编译,如使用一下命令行:

  F:>csc.exe Form1.cs
  F:>csc.exe TestForm1.cs

  编译后生成两个.exe文件。

  首先运行第一个程序,显示Form1窗体,然后运行第二个程序,显示TestForm1窗体。

  在TestForm1窗体上点击button1按钮(向Form1窗体上的button1发送消息)此时显示对话框提示“This is button1 click!”。

  在TestForm1窗体上点击button2按钮(向Form1窗体上的textBox1发送消息)此时在Form1上的textBox1上显示“测试aaa”。

 

public static void GoToLine(RichTextBox rtb, int rownumber)
{
  //在vs 2003 下可以通过以下代码实现
  int i = 1;
  int b = 0;
  foreach(string s in rtb.Lines) //不要改为for语句
  {
    if(i<rownumber) b += s.Length+1; else break;
    i++;
  }
  rtb.SelectionStart = b -1;
  rtb.SelectionLength = 0;
  rtb.Focus();
  rtb.ScrollToCaret();
  */

  //在vs 2005 下由于RichTextBox有成员GetFirstCharIndexFromLine,就方便多了。通过以下代码实现
  rtb.SelectionStart = rtb.GetFirstCharIndexFromLine(rownumber-1) – 1;
  rtb.SelectionLength = 0;
  rtb.Focus();
  rtb.ScrollToCaret();
 
}

注:Microsoft Visual Studio 2005 Beta1 version 8.0.40607.16
Microsoft .NET Framework version 2.0.40607

 

using System; using System.Security.Cryptography; using System.Text; namespace Utility { public class PasswordGenerator { public PasswordGenerator() { this.Minimum = DefaultMinimum; this.Maximum = DefaultMaximum; this.ConsecutiveCharacters = false; this.RepeatCharacters = true; this.ExcludeSymbols = false; this.Exclusions = null; rng = new RNGCryptoServiceProvider(); } protected int GetCryptographicRandomNumber(int lBound, int uBound) { // 假定 lBound >= 0 &#038;&#038; lBound < uBound // 返回一个 int >= lBound and < uBound uint urndnum; byte[] rndnum = new Byte[4]; if (lBound == uBound-1) { // 只有iBound返回的情况 return lBound; } uint xcludeRndBase = (uint.MaxValue - (uint.MaxValue%(uint)(uBound-lBound))); do { rng.GetBytes(rndnum); urndnum = System.BitConverter.ToUInt32(rndnum,0); } while (urndnum >= xcludeRndBase); return (int)(urndnum % (uBound-lBound)) + lBound; } protected char GetRandomCharacter() { int upperBound = pwdCharArray.GetUpperBound(0); if ( true == this.ExcludeSymbols ) { upperBound = PasswordGenerator.UBoundDigit; } int randomCharPosition = GetCryptographicRandomNumber(pwdCharArray.GetLowerBound(0), upperBound); char randomChar = pwdCharArray[randomCharPosition]; return randomChar; } public string Generate() { // 得到minimum 和 maximum 之间随机的长度 int pwdLength = GetCryptographicRandomNumber(this.Minimum, this.Maximum); StringBuilder pwdBuffer = new StringBuilder(); pwdBuffer.Capacity = this.Maximum; // 产生随机字符 char lastCharacter, nextCharacter; // 初始化标记 lastCharacter = nextCharacter = &#8216;\n&#8217;; for ( int i = 0; i < pwdLength; i++ ) { nextCharacter = GetRandomCharacter(); if ( false == this.ConsecutiveCharacters ) { while ( lastCharacter == nextCharacter ) { nextCharacter = GetRandomCharacter(); } } if ( false == this.RepeatCharacters ) { string temp = pwdBuffer.ToString(); int duplicateIndex = temp.IndexOf(nextCharacter); while ( -1 != duplicateIndex ) { nextCharacter = GetRandomCharacter(); duplicateIndex = temp.IndexOf(nextCharacter); } } if ( ( null != this.Exclusions ) ) { while ( -1 != this.Exclusions.IndexOf(nextCharacter) ) { nextCharacter = GetRandomCharacter(); } } pwdBuffer.Append(nextCharacter); lastCharacter = nextCharacter; } if ( null != pwdBuffer ) { return pwdBuffer.ToString(); } else { return String.Empty; } } public bool ConsecutiveCharacters { get { return this.hasConsecutive; } set { this.hasConsecutive = value;} } public bool ExcludeSymbols { get { return this.hasSymbols; } set { this.hasSymbols = value;} } public string Exclusions { get { return this.exclusionSet; } set { this.exclusionSet = value; } } public int Maximum { get { return this.maxSize; } set { this.maxSize = value; if ( this.minSize >= this.maxSize ) { this.maxSize = PasswordGenerator.DefaultMaximum; } } } public int Minimum { get { return this.minSize; } set { this.minSize = value; if ( PasswordGenerator.DefaultMinimum > this.minSize ) { this.minSize = PasswordGenerator.DefaultMinimum; } } } public bool RepeatCharacters { get { return this.hasRepeating; } set { this.hasRepeating = value;} } private const int DefaultMaximum = 10; private const int DefaultMinimum = 6; private const int UBoundDigit = 61; private string exclusionSet; private bool hasConsecutive; private bool hasRepeating; private bool hasSymbols; private int maxSize; private int minSize; private char[] pwdCharArray = &#8220;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 89`~!@#$^*()-_=+[]{}\\|;:&#8217;\&#8221;,./&#8221;.ToCharArray(); private RNGCryptoServiceProvider rng; } }