有需求或技術問題可以隨時跟我連絡 (MSN上線時)

顯示具有 程式技巧 標籤的文章。 顯示所有文章
顯示具有 程式技巧 標籤的文章。 顯示所有文章

2011年7月19日 星期二

LocalTime to UTC in JAVA

import java.text.SimpleDateFormat; 
import java.util.Date;
import java.util.TimeZone;
 
public class scratch {
    public static void main (String args[]) {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone (TimeZone.getTimeZone ("UTC"));
        System.out.println ("Time in UTC is " + sdf.format (now));
    }
}


This outputs:



Time in UTC is 2011-04-11 13:40:04 

2009年12月30日 星期三

XML Node 查詢操作

XML幾乎已經算是很廣泛的用於設定檔及一些資料的格式化存檔.既然如此,對它的內容的查詢就會經常的出現在程式之中,今天寫一個簡當的範例提供參考...

XML格式及內容:

<Names>
    <Name>
        <Name>Johnny</Name>
        <Tel>0926010111</Tel>
    </Name>
    <Name>
        <Name>Tim</Name>
        <Tel>0930817118</Tel>
    </Name>
</Names>

操作方式:

XmlDocument xml = new XmlDocument();
xml.Load(new StreamReader(myXmlString)); //myXmlString為上面檔案檔名
XmlNodeList xnList = xml.SelectNodes("/Names/Name");
foreach (XmlNode xn in xnList)
{
  string Name = xn["Name"].InnerText;
  string Tel = xn["Tel"].InnerText;
  Console.WriteLine("Name: {0} Tel: {1}", Name, Tel);
}

輸出:

Name: Johnmy Tel: 0926010111

Name: Tim Tel: 0930817118




檔案屬性操作

(1)取得檔案屬性

string filePath = @"c:\test.txt"; 

FileAttributes fileAttributes = File.GetAttributes(filePath);

(2)設定檔案屬性

// 清除所有檔案屬性

File.SetAttributes(filePath, FileAttributes.Normal);

// 只設定封存及唯讀屬性

File.SetAttributes(filePath, FileAttributes.Archive | FileAttributes.ReadOnly);

(3)檢查檔案屬性

// 檢查檔案是否有唯讀屬性

bool isReadOnly = ((File.GetAttributes(filePath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly);

// 檢查檔案是否有隱藏屬性

bool isHidden = ((File.GetAttributes(filePath) & FileAttributes.Hidden) == FileAttributes.Hidden);

// 檢查檔案是否有封存屬性

bool isArchive = ((File.GetAttributes(filePath) & FileAttributes.Archive) == FileAttributes.Archive);

// 檢查檔案是否有系統屬性

bool isSystem = ((File.GetAttributes(filePath) & FileAttributes.System) == FileAttributes.System);

(4)加入某些屬性給檔案

// 設定隱藏屬性   

File.SetAttributes(filePath, File.GetAttributes(filePath) | FileAttributes.Hidden);

// 設定封存及唯讀屬性  

File.SetAttributes(filePath, File.GetAttributes(filePath) | (FileAttributes.Archive | FileAttributes.ReadOnly));




2009年12月11日 星期五

身分證ID產生程式

最近有網友跟我詢問身分證ID的產生方式(他的學校作業),特地寫了一隻小程式分享大家.

選擇出生地及性別的方式

2009-12-11 下午 04-24-26 隨機產生的方式

2009-12-11 下午 04-24-43

身分證ID驗證規則,請參考我的另一篇文章

http://nelsonliublog.blogspot.com/2009/08/blog-post_12.html

或是 我的接案網頁

http://deepbrainstudio.blogspot.com/2009/08/blog-post.html 

請不要拿去做壞事喔,不然我會很傷心的...

檔案下載 :

執行檔[MD5 : fee39a74124153a167a4aa77588e6b66]

 

Source Code[MD5 : f0a48f7d076f5eeab9a3d5269c77f245]



2009年9月15日 星期二

常用時間(DateTime)字串格式整理

時間字串的格式化輸出是經常會用到的,尤其是程式會是系統的Log檔,為了明確的紀錄時間或是讓分析Log的工作更簡單,格式化的輸出尤其重要,一般來說都會使用String.Format來達到格式化的目的.看以下範例...

(1)自訂時間格式

specifiers
y 年
M 月
d 日
h 12小時制
H 24小時制
m 分
s 秒
f 毫秒
F 毫秒(不補0)
t 上午/下午
z 時區

DateTime myDT = new DateTime(2008, 3, 9, 16, 5, 7, 123);

String.Format("{0:y yy yyy yyyy}", myDT);   輸出=> "8 08 008 2008" 年份
String.Format("{0:M MM MMM MMMM}", myDT);  輸出=> "3 03 Mar March"月份
String.Format("{0:d dd ddd dddd}", myDT);  輸出=> "9 09 Sun Sunday" 日期
String.Format("{0:h hh H HH}",     myDT);  輸出=> "4 04 16 16"  時制 12/24
String.Format("{0:m mm}",          myDT);  輸出=> "5 05" 分
String.Format("{0:s ss}",          myDT);  輸出=> "7 07" 秒
String.Format("{0:f ff fff ffff}", myDT);  輸出=> "1 12 123 1230" 毫秒
String.Format("{0:F FF FFF FFFF}", myDT);  輸出=> "1 12 123 123" 毫秒(不補0)
String.Format("{0:t tt}",          myDT);  輸出=> "P PM"  上/下午
String.Format("{0:z zz zzz}",      myDT);  輸出=>  "-6 -06 -06:00"   時區

 

(2)標準時間格式(Framework提供)

Specifier     DateTimeFormatInfo         property Pattern value 
t                   ShortTimePattern              h:mm tt
d                  ShortDatePattern               M/d/yyyy
T                  LongTimePattern               h:mm:ss tt
D                 LongDatePattern                 dddd, MMMM dd, yyyy
f                  (combination of D and t)     dddd, MMMM dd, yyyy h:mm tt
F                 FullDateTimePattern            dddd, MMMM dd, yyyy h:mm:ss tt
g                 (combination of d and t)      M/d/yyyy h:mm tt
G                (combination of d and T)      M/d/yyyy h:mm:ss tt
m, M            MonthDayPattern                MMMM dd
y, Y             YearMonthPattern                MMMM, yyyy
r, R             RFC1123Pattern                   ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
s                 SortableDateTi­mePattern     yyyy'-'MM'-'dd'T'HH':'mm':'ss
u                 UniversalSorta­ble                yyyy'-'MM'-'dd HH':'mm':'ss'Z'
                   DateTimePat­tern

String.Format("{0:t}", myDT);  輸出=>   "4:05 PM"                        
String.Format("{0:d}", myDT);  輸出=>   "3/9/2008"                       
String.Format("{0:T}", myDT);  輸出=>   "4:05:07 PM"                    
String.Format("{0:D}", myDT);  輸出=>   "Sunday, March 09, 2008"         
String.Format("{0:f}", myDT);  輸出=>   "Sunday, March 09, 2008 4:05 PM" 
String.Format("{0:F}", myDT);  輸出=>   "Sunday, March 09, 2008 4:05:07 PM"
String.Format("{0:g}", myDT);  輸出=>   "3/9/2008 4:05 PM"        
String.Format("{0:G}", myDT);  輸出=>   "3/9/2008 4:05:07 PM"           
String.Format("{0:m}", myDT);  輸出=>   "March 09"                      
String.Format("{0:y}", myDT);  輸出=>   "March, 2008"                   
String.Format("{0:r}", myDT);  輸出=>   "Sun, 09 Mar 2008 16:05:07 GMT" 
String.Format("{0:s}", myDT);  輸出=>   "2008-03-09T16:05:07"          
String.Format("{0:u}", myDT);  輸出=>   "2008-03-09 16:05:07Z"



2009年9月2日 星期三

網頁內含圖檔下載程式

蠻久以前寫的一個小程式,介紹給大家...

程式目的:下載網頁內含的JPG檔到C:\MY_PIC內

(當然你也可以透過IE右鍵另存圖片...哈哈)

程式原理:利用WebBrowser控制項,讀取網頁HTML Document,然後利用正則表達式,找出HTML內所有的圖檔路徑並下載.

正則表達式:

(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?

程式Layout說明:

2009-9-2 上午 10-31-10

以下列網頁為例:

http://dcview.com.tw/gallery/showmsg.asp?msgid=774265&place=1&posit=1

2009-9-2 上午 10-58-09 2009-9-2 上午 11-01-46

2009-9-2 上午 11-12-15

2009-9-2 上午 11-13-49

重要程式碼節錄

解析網頁

ArrayList FilesArrayList = new ArrayList();
MatchCollection FilesMachCollection = Regex.Matches(myWB.DocumentText, textBox2.Text, RegexOptions.Compiled);
for (int i = 0; i < FilesMachCollection.Count; i++)
{
      FilesArrayList.Add(FilesMachCollection[i].ToString());
}

其中textBox2.Text = (http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?

 

下載圖檔

string myPath = @"C:\MY_PIC\";
using (WebClient client = new WebClient())
{
    if (!Directory.Exists(myPath))
    {
        Directory.CreateDirectory(myPath);
        a = 0;
    }
    else
    {
        a = Directory.GetFiles(myPath).Length + 1; //計算下一圖檔檔名序號
    }
    progressBar1.Maximum = 100;
    progressBar1.Minimum = 0;
    progressBar1.Value = 0;
    for (int i = 0; i < listBox1.Items.Count; i++)
    {
        Application.DoEvents();
        string fileName = myPath + a.ToString().PadLeft(10, '0') + ".JPG";
        client.DownloadFile(listBox1.Items[i].ToString(), fileName);
        Application.DoEvents();
        double nowValue = (100 * (i + 1)) / listBox1.Items.Count;
        progressBar1.Value = (int)nowValue;
        Application.DoEvents();
        a++;
    }
}

執行檔[MD5 : 3076129e886d503a20022ae7cabeda8e]

 

Source Code[MD5 : 03800d5e8d311eeb7bf48193fbb3c709]



2009年8月27日 星期四

2009年8月26日 星期三

Reflection in C#

System.Reflection 這個Name Space,有著強大的Hack Function.

以下是MSDN對它的一些描述

反映(Reflection)概觀

Common Language Runtime 載入器可管理 應用程式定義域,這些定義域可在具有相同應用程式範圍的物件周圍構成定義的界限。這個管理包括載入各個組件至適當應用程式定義域,和控制各個組件內型別階層架構的記憶體配置。

組件包含模組,模組包含型別,而型別包含成員。反映提供封裝組件、模組和型別的物件。您可以使用反映,動態建立型別的執行個體、繫結型別至現有物件,或從現有物件取得型別。您可以接著叫用型別的方法,或存取它的欄位和屬性。反映的一般用法如下所示:

  • 使用 Assembly 定義並載入組件、載入組件資訊清單 (Assembly Manifest) 中列出的模組,和從這個組件找出型別並建立它的執行個體。

  • 使用 Module 探索資訊,例如包含模組和模組中類別的組件。您也可以取得所有全域方法或是在模組上定義的其他特定非全域方法。

  • 使用 ConstructorInfo 探索資訊,例如名稱、參數、存取修飾詞 (例如 publicprivate),以及建構函式的實作 (Implementation) 詳細資訊 (例如 abstractvirtual)。使用 TypeGetConstructorsGetConstructor 方法,叫用特定的建構函式。

  • 使用 MethodInfo 探索資訊,例如名稱、傳回型別、參數、存取修飾詞 (例如 publicPrivate),以及方法的實作詳細資訊 (例如 abstractvirtual)。使用 TypeGetMethodsGetMethod 方法,叫用特定方法。

  • 使用 FieldInfo 探索資訊,例如名稱、存取修飾詞 (例如 publicprivate),以及欄位的實作詳細資訊 (例如 static),並取得或設定欄位值。

  • 使用 EventInfo 探索資訊,例如名稱、事件處理常式資料型別、自訂屬性、宣告型別和事件的反映型別,並加入或移除事件處理常式。

  • 使用 PropertyInfo 探索資訊,例如名稱、資料型別、宣告型別、反映型別和屬性的唯讀或可寫入狀態,並取得或設定屬性值。

  • 使用 ParameterInfo 探索資訊,例如參數的名稱、資料型別、參數是否為輸入或輸出參數,和方法簽章 (Signature) 中參數的位置。

  • 使用 CustomAttributeData 探索在應用程式定義域的僅限反映內容中工作時,關於自訂屬性的資訊。CustomAttributeData 讓您可以檢查屬性,而不需要建立這些屬性的執行個體。

System.Reflection.Emit 命名空間的類別提供反映的特殊形式,允許您在 Run Time 建置型別。

反映也可以用來建立稱為型別瀏覽器的應用程式,允許使用者選取型別並接著檢視那些型別的資訊。

反映還有其他用法。語言編譯器,例如 JScript,會使用反映建構符號表。 System.Runtime.Serialization 命名空間中的類別會使用反映存取資料,並判斷哪個欄位要保存 (Persist)。 System.Runtime.Remoting 命名空間中的類別會透過序列化 (Serialization) 間接使用反映。

 

不說廢話,來一個範例看看它的威力,先看一下程式大概架構,如下圖所示

2009-8-26 下午 04-12-53 方案中有兩個專案,(1)TEST(2)物件Reflection

(1)TEST : 在 FormTest.cs 新增 (其他啥事都不做)

private int Add(int a, int b)
{
    return a + b;
}

(2)物件Reflection : FormReflection Layout如上圖,FormReflection.cs新增兩個Button Event

private void button2_Click(object sender, EventArgs e)
{
    OpenFileDialog myOFD = new OpenFileDialog();
    myOFD.Filter = "*.exe|*.EXE";
    if (myOFD.ShowDialog() == DialogResult.OK)
        textBox4.Text = myOFD.FileName;
}
private void button1_Click(object sender, EventArgs e)
{
    Assembly myAssembly = Assembly.LoadFile(textBox4.Text);
    Type myType = myAssembly.GetType("EST.FormTEST");
    object MyInstance = Activator.CreateInstance(myType);
    textBox3.Text = myType.InvokeMember("Add",
                    BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
                    null, MyInstance, new object[] { int.Parse(textBox1.Text), int.Parse(textBox2.Text) }).ToString();
}

原理:

按下FormReflection button2,選取Test.exe所在路徑

按下FormReflection button1,Call Test.exe 的TEST.FormTEST Add(…),完成運算

2009-8-26 下午 04-48-18

以上只是一個最簡單的範例,Reflection還有很多很強大的功能,有待研究...

Source Code [MD5 : 4fbf53d221d4605190bc048f57e32b39]



陣列排序(Arrays Sorting) in C#

陣列可以透過Static Method Array.Sort來達到排序的目的.

(1) C# 基礎型別(Primitive types :int, double or string)

Int Array :

int[] intArray = new int[5] { 8, 10, 2, 6, 3 };
Array.Sort(intArray);
foreach (int i in intArray)
   Console.Write(i + " ");

輸出: 2 3 6 8 10

String Array :

string[] stringArray = new string[5] { "X", "B", "Z", "Y", "A" };
Array.Sort(stringArray);
foreach (string str in stringArray)
   Console.Write(str + " ");

輸出: A B X Y Z

(2)透過Delegate對自訂型別排序

定義類別

class User
{
     public string Name;
     public int Age;
     public User(string Name, int Age)

     {

        this.Name = Name;
        this.Age = Age;
     }
}

定義使用者資料

User[] users = new User[3]
              { new User("Betty", 23),
                new User("Susan", 20),
                new User("Lisa", 25)
              };

//根據姓名排序  Inline delegate
Array.Sort(users, delegate(User user1, User user2)
{
    return user1.Name.CompareTo(user2.Name);
}
);
foreach (User user in users) Console.Write(user.Name + ":" + user.Age + " "); 

輸出: Betty:23 Lisa:25 Susan:20

//根據年齡排序  Method Delegate
delegate int mySort(User user1, User user2);


Array.Sort(users, mySortMethod);
foreach (User user in users) Console.Write(user.Name + ":" + user.Age + " ");

private int mySortMethod(User user1, User user2)
{
       return user1.Age.CompareTo(user2.Age);
}

輸出: Susan20 Betty23 Lisa25)

(3)透過IComparable對自訂型別排序

定義類別

public class User : IComparable
{
  public string Name;
  public int Age;
  public User(string Name, int Age)
  {
     this.Name = Name;
     this.Age = Age;
  } 

  // implement IComparable interface
  public int CompareTo(object obj)
  {
    if (obj is User)
    {
      return this.Name.CompareTo((obj as User).Name);//根據姓名排序
    }
    throw new ArgumentException("Object is not a User");
  }
}

定義使用者資料

User[] users = new User[3]
              { new User("Betty", 23),
                new User("Susan", 20),
                new User("Lisa", 25)
              };

//根據姓名排序

Array.Sort(users);

設定 DoubleBuffered 屬性(Property)

下面的範例是如何設定 protected 的Control.Double­Buffered屬性為True,這是一個經常需要去特別修改的屬性,這樣一來就可以避免重繪控制項時造成的螢幕閃爍.

所有的控制項都有Double­Buffered屬性,但是此屬性是被[protected]保護起來,底下這個Function,利用了Reflection來存取 non-public 的methods 以及properties,如此一來就可以輕易的修改Double­Buffered屬性...

範例程式:

// set instance non-public pr operty with name "DoubleBuffered" to true typeof
public static void SetDoubleBuffered(Control control)
{
       typeof(Control).InvokeMember("DoubleBuffered", 
                          BindingFlags.SetProperty |BindingFlags.Instance | BindingFlags.NonPublic, 
                          null, control, new object[] { true } );
}



2009年8月24日 星期一

保護(加密) 應用程式組態檔 (App.config)

VS2005中提供的一個方便的功能就是[專案]中->[Properties]->[Settings.settings],一個方常方便的功能,提供了User層級及Application層級的應用程式設定值設定.

可以透過VS2005的功能修改及讀取,甚至是Reset為原始值.(下兩圖所示)

2009-8-24 上午 09-34-20

2009-8-24 上午 09-49-59

  但是有時候不想要讓使用者動到Application層級的設定值,或是讓人家知道程式的重要設定值,你可以進行加密的動作,像是下圖

2009-8-24 上午 09-26-23

以下是一個簡單的範例Step by Step教你達成...

(1)建立你的應用程式及設定你的Application Setting

2009-8-24 上午 10-09-512009-8-24 上午 10-12-30

(2)在Form1建構式中加入這行

this.Text = MyDemo.Properties.Settings.Default.MyApplicationName;

下圖所示

2009-8-24 上午 10-23-39

(3)新增一個安裝程式類別 如下圖

2009-8-24 上午 10-30-47

2009-8-24 上午 10-32-25

2009-8-24 上午 10-33-15

2009-8-24 上午 10-33-42

(4)於安裝程式類別 override Install Method & Add ProtectSection Function

using System.Configuration;

public override void Install(System.Collections.IDictionary stateSaver)
{
    base.Install(stateSaver);

    //get Protected Configuration Provider name from custom action parameter
    string sectionName = this.Context.Parameters["sectionName"];

    //get Protected Configuration Provider name from custom action parameter
    string provName = this.Context.Parameters["provName"];

    // get the exe path from the default context parameters
    string exeFilePath = this.Context.Parameters["assemblypath"];

    //encrypt the configuration section
    ProtectSection(sectionName, provName, exeFilePath);
}
private void ProtectSection(string sectionName, string provName, string exeFilePath)
{
    Configuration config = ConfigurationManager.OpenExeConfiguration(exeFilePath);
    ConfigurationSection section = config.GetSection(sectionName);

    if (!section.SectionInformation.IsProtected)
    {
        //Protecting the specified section with the specified provider
        section.SectionInformation.ProtectSection(provName);
    }
    section.SectionInformation.ForceSave = true;
    config.Save(ConfigurationSaveMode.Modified);
}

2009-8-24 上午 10-41-23

(5)打開app.config 並加入下面Section

<configProtectedData>
    <providers>
      <add useMachineProtection="true" name="DPAPIProtection"
          type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration,&#xD;&#xA;  Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </providers>
  </configProtectedData>

2009-8-24 上午 10-45-58 

(6)新增一安裝專案(加密部分需安裝後才會看的出來)2009-8-24 上午 10-48-202009-8-24 上午 10-49-59 2009-8-24 上午 10-50-50 (7)修改安裝專案內容

2009-8-24 上午 10-54-532009-8-24 上午 10-58-02 2009-8-24 上午 10-59-182009-8-24 上午 11-04-532009-8-24 上午 11-05-12 修改屬性內容如下

/sectionName="applicationSettings/MyDemo.Properties.Settings" /provName="DPAPIProtection"

2009-8-24 上午 11-11-45

(8) Add Ref System.Configuration

2009-8-24 上午 11-18-18 2009-8-24 上午 11-19-04

(9) 編譯程式 (如果有按上面步驟操作應該會編譯成功)

2009-8-24 上午 11-15-35

(10)安裝應用程式

2009-8-24 上午 11-26-19

安裝完後,大功告成...

 

確認結果

2009-8-24 上午 11-29-44

2009-8-24 上午 11-31-17

範例程式[MD5 : c77f290441698787fc94d3325a2b41b4]

Source Code[MD5 : 4339ec62e8bfed90c3d6efa177152456]



2009年8月20日 星期四

螢幕結取與鍵盤HOOK 程式修正

剛剛測試了一下程式,發現記憶體越吃越兇...

於是修正一下程式

打開Source Code Form1.cs 修正底下(粗體字部分 請新增即可)

private void timer_Capture_Tick(object sender, EventArgs e)
{
    Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
    gfxScreenshot = Graphics.FromImage(bmpScreenshot);  
    gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);  
    string FileName = Path.Combine(textBox_FolderName.Text,string.Format(@"{0}.jpg", DateTime.Now.Ticks.ToString()));
    bmpScreenshot.Save(FileName, System.Drawing.Imaging.ImageFormat.Png);
    bmpScreenshot.Dispose();
    gfxScreenshot.Dispose();
}
private void timer_checkESC_Tick(object sender, EventArgs e)
{
    Application.DoEvents();
    GC.Collect();
    if (StopFlg)
        EndProcess();
}

不想修改者,這裡直接下再使用...

程式[MD5 : baac548d02f802c73640f5feda7a53a6]



鍵盤 Hook的應用

上篇文章提到Keyboard Hook,一般都會以為只能用在一些Hack程式(鍵盤側錄...),但是有很多程式是需要這個Keyboard Hook的支援,特別是那些失去Focus時候的應用程式,無法用KeyDown Event捕捉使用者的訊息,所以想要透過鍵盤的操控(快速鍵)達到"開始" ”停止" “擷取"……都可以透過這個方式達到目的.

底下是我寫的一個範例:

用途:全螢幕擷取程式,使用者可以設定圖檔存放處,擷取頻率...

當使用這按下[開始],程式最小化開始進行擷取,一直當使用者按下[Esc]就立即停止擷取,並將程式帶至桌面前景...

2009-8-20 下午 01-35-25

2009-8-20 下午 01-42-18

重要程式片段:

private void button_Start_Click(object sender, EventArgs e) 

     if (m_HookHandle == 0) 
         { 
             using (Process curProcess = Process.GetCurrentProcess()) 
             using (ProcessModule curModule = curProcess.MainModule) 
             { 
                 m_KbdHookProc = new HookProc(Form1.KeyboardHookProc); 
                 m_HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, m_KbdHookProc, GetModuleHandle(curModule.ModuleName), 0); 
             } 
             if (m_HookHandle == 0) 
             { 
                 MessageBox.Show("呼叫 SetWindowsHookEx 失敗!"); 
                 return; 
             } 
             StartProcess(); 
         } 
}

private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam) 

        // 當按鍵按下及鬆開時都會觸發此函式,這裡只處理鍵盤按下的情形。 
        bool isPressed = (lParam.ToInt32() & 0x80000000) == 0; 
        if (nCode < 0 || !isPressed) 
        { 
            return CallNextHookEx(m_HookHandle, nCode, wParam, lParam); 
        }

        // 取得欲攔截之按鍵狀態 
        KeyStateInfo escKey = KeyboardInfo.GetKeyState(Keys.Escape); 
        if (escKey.IsPressed) 
        { 
            System.Diagnostics.Debug.WriteLine("ESC Pressed!"); 
            bool ret = UnhookWindowsHookEx(m_HookHandle); 
            if (ret == false) 
            { 
                MessageBox.Show("呼叫 UnhookWindowsHookEx 失敗!"); 
                return 0; 
            } 
            m_HookHandle = 0; 
            StopFlg = true; 
            return 0; 
        } 
        return CallNextHookEx(m_HookHandle, nCode, wParam, lParam); 
  }

程式 [MD5 : 3bf4c56247725d8437605e17189626ef]

 

Source Code [MD5 : 6301e4c7e651ffa46959259adbd21447]