無法查看此摘要。請 按這裡查看文章。
歡迎跟我連絡
免安裝程式...哈哈 歡迎聊天
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 探索資訊,例如名稱、參數、存取修飾詞 (例如 public 或 private),以及建構函式的實作 (Implementation) 詳細資訊 (例如 abstract 或 virtual)。使用 Type 的 GetConstructors 或 GetConstructor 方法,叫用特定的建構函式。
-
使用 MethodInfo 探索資訊,例如名稱、傳回型別、參數、存取修飾詞 (例如 public 或 Private),以及方法的實作詳細資訊 (例如 abstract 或 virtual)。使用 Type 的 GetMethods 或 GetMethod 方法,叫用特定方法。
-
使用 FieldInfo 探索資訊,例如名稱、存取修飾詞 (例如 public 或 private),以及欄位的實作詳細資訊 (例如 static),並取得或設定欄位值。
-
使用 EventInfo 探索資訊,例如名稱、事件處理常式資料型別、自訂屬性、宣告型別和事件的反映型別,並加入或移除事件處理常式。
-
使用 PropertyInfo 探索資訊,例如名稱、資料型別、宣告型別、反映型別和屬性的唯讀或可寫入狀態,並取得或設定屬性值。
-
使用 ParameterInfo 探索資訊,例如參數的名稱、資料型別、參數是否為輸入或輸出參數,和方法簽章 (Signature) 中參數的位置。
-
使用 CustomAttributeData 探索在應用程式定義域的僅限反映內容中工作時,關於自訂屬性的資訊。CustomAttributeData 讓您可以檢查屬性,而不需要建立這些屬性的執行個體。
System.Reflection.Emit 命名空間的類別提供反映的特殊形式,允許您在 Run Time 建置型別。
反映也可以用來建立稱為型別瀏覽器的應用程式,允許使用者選取型別並接著檢視那些型別的資訊。
反映還有其他用法。語言編譯器,例如 JScript,會使用反映建構符號表。 System.Runtime.Serialization 命名空間中的類別會使用反映存取資料,並判斷哪個欄位要保存 (Persist)。 System.Runtime.Remoting 命名空間中的類別會透過序列化 (Serialization) 間接使用反映。
不說廢話,來一個範例看看它的威力,先看一下程式大概架構,如下圖所示
方案中有兩個專案,(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(…),完成運算
以上只是一個最簡單的範例,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.DoubleBuffered屬性為True,這是一個經常需要去特別修改的屬性,這樣一來就可以避免重繪控制項時造成的螢幕閃爍.
所有的控制項都有DoubleBuffered屬性,但是此屬性是被[protected]保護起來,底下這個Function,利用了Reflection來存取 non-public 的methods 以及properties,如此一來就可以輕易的修改DoubleBuffered屬性...
範例程式:
// 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為原始值.(下兩圖所示)
但是有時候不想要讓使用者動到Application層級的設定值,或是讓人家知道程式的重要設定值,你可以進行加密的動作,像是下圖
以下是一個簡單的範例Step by Step教你達成...
(1)建立你的應用程式及設定你的Application Setting
(2)在Form1建構式中加入這行
this.Text = MyDemo.Properties.Settings.Default.MyApplicationName;
下圖所示
(3)新增一個安裝程式類別 如下圖
(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);
}
(5)打開app.config 並加入下面Section
<configProtectedData>
<providers>
<add useMachineProtection="true" name="DPAPIProtection"
type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration,
 Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</configProtectedData>
(6)新增一安裝專案(加密部分需安裝後才會看的出來)
(7)修改安裝專案內容
/sectionName="applicationSettings/MyDemo.Properties.Settings" /provName="DPAPIProtection"
(8) Add Ref System.Configuration
(9) 編譯程式 (如果有按上面步驟操作應該會編譯成功)
(10)安裝應用程式
安裝完後,大功告成...
確認結果
範例程式[MD5 : c77f290441698787fc94d3325a2b41b4]
Source Code[MD5 : 4339ec62e8bfed90c3d6efa177152456]
2009年8月21日 星期五
Helpsvc.exe佔用大量CPU資源解決辦法
今天早上電腦開機進入DeskTop後,發現我的硬碟狂奔,打開[工作管理員],發現Helpsvc正佔用我的CUP & MEM大量資源,查了一下問題,提供給大家參考...
程式名稱: helpsvc 或者 helpsvc.exe
正式名稱: Microsoft Helpsvc
描述: helpsvc.exe是Windows 2000以及更高版本Windows的幫助服務。
出版者: Microsoft
屬於: Microsoft Help Center Service
系統進程: 否
後台程序: 是
使用網絡: 否
硬件相關: 否
常見錯誤: 未知N/A
內存使用: 未知N/A
安全等級 (0-5): 0
間諜軟件: 否
廣告軟件: 否
病毒: 否
木馬: 否
關閉程序:
開始->執行->gpedit.msc->使用者設定->系統管理範本->系統-> 不要執行指定的Windows應用程序 雙擊它,選啟用,再選顯示,再選添加,輸入helpsvc.exe確定,應用,再確定.
注意: 關閉後,您將無法使用微軟"說明與支援"服務.
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]就立即停止擷取,並將程式帶至桌面前景...
重要程式片段:
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]
2009年8月18日 星期二
鍵盤 Keyboard Hook
一個簡單的鍵盤Hook程式...
基本上都是Win32API兜出來的...
SetWindowsHookEx() , UnhookWindowsHookEx() , CallNextHookEx() , GetCurrentThreadId() ,GetModuleHandle()
目前只針對 Ctrl , Alt , Shift , F8 進行觸發後紀錄...
有興趣的人可以自行修改,底下有Source Code
Source Code ( MD5 : 7c32ae81d92a624111c655ea2a2bc196 )
2009年8月17日 星期一
Indexer(索引器) in C#
透過索引器機制,能夠讓你像陣列一樣的爲物件編寫索引值,這是屬性提供的一個有效率的方式來管理類別的實體資料,看以下範例
(1)建立Telephone Class
public class Telephnoe
{
private string[] _telephone = new string[3];
public string this[int index]
{
get
{
if(index >=0 || index < _telephone.Length)
{
return _telephone[index];
}
return string.Empty;
}
set
{
if (index >= 0 || index < _telephone.Length)
{
_telephone[index] = value;
}
}
}
}
(2)建立Person Class
public class Person
{
public string Name { get; set; }
public Telephone Telephones = new Telephone();
}
使用範例:
// 宣告 Person 類別物件變數 Person
Person myPerson = new Person();
// 設定一般 Name 屬性,無法帶入參數
person.Name = "王小明";
// 設定可代入參數的 Telephones 屬性
person.Telephones[0] = "07-3333333";
person.Telephones[1] = "0960666333";
// 讀取一般性 Name 屬性
Console.WriteLine(person.Name);
// 設定可代入參數的 Telephones 屬性
Console.WriteLine(person.Telephones[0]);
Console.WriteLine(person.Telephones[1]);
輸出結果:
王小明
電話:07-3333333
電話:0960666333
2009年8月16日 星期日
Int / String to Enum in C#
2009年8月14日 星期五
防止程式重複啟動的方法(二)
曾經在一篇文章介紹過這個方法(請參考如何讓你的程式只能啟動一次 in C#)
今天再紹另一種方法 System.Diagnostics命名空間中的Process.GetProcessesByName…
範例程式如下:
Using System.Diagnostics;
...
private void FormMain_Load(object sender, EventArgs e)
{
if (Process.GetProcessesByName(
Process.GetCurrentProcess().ProcessName).Length > 1)
{
Dispose();
}
}
在Form Load Event中,新增這段程式碼即可...
2009年8月12日 星期三
2 8 10 16進位制轉換
UI Layout如下圖所示:
重要程式碼:
namespace 進制轉換
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
comboBox_From.SelectedIndex = 0;
comboBox_To.SelectedIndex = 2;
textBox_Source.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
textBox_Result.Text = Convert2UrBase(textBox_Source.Text, int.Parse(comboBox_From.SelectedItem.ToString()), int.Parse(comboBox_To.SelectedItem.ToString())); }
public string Convert2UrBase(String Input_Value, int FromBase, int ToBase)
{
long RtnValue;
try
{
RtnValue = Convert.ToInt64(Input_Value, FromBase);
}
catch (Exception other)
{
RtnValue = 0;
}
return Convert.ToString(RtnValue, ToBase);
}
}
}
2009年8月11日 星期二
修改字串編碼方式(Encoding)
有時候會出現顯示會出現亂碼,通常是編碼方式出了問題.
我們可以理用Encoding來解決這個問題...
範例程式:
string Source = "轉換編碼方式範例字串";
byte[] Target_BIG5 = Encoding.Default.GetBytes(Source ); //將字串轉為byte[], 中文版Default就是指BIG5編碼
byte[] Target_UTF8 = Encoding.Convert(Encoding.Default, Encoding.UTF8, Target_BIG5 );//轉碼Encoding.Convert(Source Encoder,Target Encoder , Source Variable)
MessageBox.Show(Encoding.UTF8.GetString(Target_UTF8 ));//顯示轉為UTF8後的字串 
2009年7月6日 星期一
VS2005 屬性視窗 (Property Window) 不見了
今天早上開啟VS2005時發現,屬性視窗 (Property Window) 不見了,怎麼都叫不出來,這還得了...
趕緊上網用Google及Bing查詢結果,好像只有重新安裝一途,因為也嘗試過修復,依然是叫不出屬性視窗...
正打算重新安裝時,突然想到"工具"->"匯出及匯入設定",試看看說不一定可以死馬當活馬醫...
打開候選取"匯入選取的環境設定"
然後"瀏覽",選取檔案
然後選擇"CurrentSettings.vssettings",按OK.
檔案位於->..\Documents and Settings\(user name)\My Documents\Visual Studio 2005\Settings
匯入成功後,重新啟動VS2005,終於可以叫出"屬性視窗",哈哈....成功了,不用重新安裝....

