2012年1月31日 星期二

在虛擬機器(Vitual Machine)中擴充硬碟

使用虛擬機器最重要的好處之一,就是可以彈性的擴充硬體
硬體的擴充動作相較於實體機器來說,就少掉了更新硬體這一步驟
(當然要在開虛擬機器的實體機器的硬體限制下)
而Windows在更新CPU或記憶體都是自動完成的
所以在虛擬機器上擴充這兩者都僅僅需要關機,設定,開機三個步驟

如果是一般的硬碟擴充,只要先在虛擬機器的設定中延伸(Expand)硬碟

再到作業系統裡面使用內建的diskpart將同一個硬碟擴充即可

C:\Documents and Settings\Administrator>diskpart

Microsoft DiskPart version 5.2.3790.3959
Copyright (C) 1999-2001 Microsoft Corporation.
On computer: WIN2K3X86

DISKPART> list volume

Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 C NTFS Partition 15 GB Healthy System
Volume 1 D CD-ROM 0 B Healthy
Volume 2 E New Volume NTFS Partition 20 GB Healthy

DISKPART> select volume 2

Volume 2 is the selected volume.

DISKPART> extend

DiskPart successfully extended the volume.

DISKPART> list volume

Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 C NTFS Partition 15 GB Healthy System
Volume 1 D CD-ROM 0 B Healthy
* Volume 2 E New Volume NTFS Partition 21 GB Healthy

DISKPART>


另外,在Windows 2003中
因為保護作業系統的檔案,所以無法變更系統磁碟的大小
這時候就需要一點小技巧,在把系統碟延伸後
先將系統碟掛到另外一台機器當作一般磁碟並擴充
此時用原本的虛擬機器開機,就會發現系統磁碟大小已經更改成功了

--
參考資料
How to Extend Windows Boot Volumes in VMware
如何擴充 VMware 虛擬磁碟及作業系統容量

2011年1月7日 星期五

常見開源協議(Open Source License)的比較

開放原始碼這樣的想法非常崇高,藉由自由分享各自的程式碼
讓軟體的發展可以更加的快速而且安全
(透明度可以讓全世界一起除錯,而且沒辦法藏後門)

但是對於"自由",大家的想法都不太一樣
比如說,如果有人拿你寫的程式去賣錢呢?
這種顧慮會讓很多開發者不願意分享,所以開源協議就出現了
目的就是,讓作者可以在被保護的狀況下
依照期待(選擇的開源協議)的讓全世界的人一起分享

目前常見的開源協議大都經過Open Source Initiative批准
協議書的全文都可以在Open Source Licenses找到
(從協議的數量就可以看出,這方面也是相當的"自由")
最常見的有GPL, GNU General Public License, LGPL, The GNU Lesser General Public License, BSD License
這些協議的一個共同點,就是再發佈的時候需要伴隨原有的協議

其中最嚴厲(崇尚自由,並要求所有人一起崇尚自由)的是GPL
強硬的要求(傳染)所有"引用/修改/衍生"GPL授權的程式碼的軟體
也必須採用GPL授權,並提供未來開發者同樣的自由,包括
1. 以任何目的執行此程式的自由
2. 再發行複製件的自由
3. 改進此程式,並公開發布改進的自由
基於這樣的規定,所以商業軟體或是不打算公開程式碼的軟體
都不得修改甚至引用GPL授權的程式碼
著名的GPL自由軟體包括Linux核心和GCC

LGPL則是將GPL條件稍微放寬,
如果僅是"引用(Link)"LGPL授權的函式庫
則不需要公開該軟體的程式碼
所以對於商業軟體來說,是可以引用LGPL的函式庫的
但是,對於"修改/衍生"LGPL授權軟體的部分,則同樣必須採用LGPL的授權
也就是一樣需要公開,且提供未來開發者同等的自由
著名的LGPL自由軟體有Mozilla跟OpenOffice.Org

BSD相對來說就寬鬆的多了
主要差異是在"修改/衍生"BSD授權的軟體時
除了版權聲明中仍需包含原來代碼中的BSD協議以外
開發者有權選擇是否要開放原始碼,或是做為商業用途

由此可以看出,如果是公司企業打算要使用開放原始碼的授權軟體的時候
BSD授權軟體可以直接使用甚至修改衍生
LGPL授權軟體則是僅能引用(Link)
GPL授權軟體則是儘量不使用,或是規避GPL的授權範圍
例如避免GPL風險的另類方法所提的方法

--
參考資料
五種開源授權規範的比較 (BSD, Apache, GPL, LGPL, MIT)
GPL 常見問題
自由軟體專案授權方式的轉換(上):不得撤銷原授權條款
自由軟體專案授權方式的轉換(下):新版本號另以更改後的授權方式釋出
在原始碼之外:編譯與安裝資訊的提供
散佈 GPL 衍生程式所須提供的原始碼範圍

2010年12月28日 星期二

在C#中讀取Excel的試算表

取出試算表的名稱後,就可以針對單一試算表進行讀取

public List LoadExcelSheet(
string excelFile, string sheetName)
{
List dataList = new List();

/// load excel file as an ole database
OleDbConnection excelDatabase =
new OleDbConnection(string.Format(
"Provider = Microsoft.Jet.OLEDB.4.0;" +
"Data Source = {0};" +
"Extended Properties='Excel 8.0;HDR=No'",
excelFile));
excelDatabase.Open();

/// query sheet from excel file
OleDbDataAdapter sheetAdapter =
new OleDbDataAdapter(string.Format(
"SELECT * FROM [{0}]", sheetName),
excelDatabase);
DataTable fileData = new DataTable();
sheetAdapter.Fill(fileData);

/// scan all cells in the sheet
foreach (DataRow row in fileData.Rows)
{
foreach (object item in row.ItemArray)
{
if (!(item is DBNull))
{
dataList.Add(item.ToString());
}
}
}

/// close and release database connection
excelDatabase.Close();

return dataList;
}

這裡值得注意的是,如果試算表中有些欄位是空的
讀出來的資料會是DBNull的型別,其餘則會是string的型別

另外,如果是手動輸入試算表名稱的話
要記得在試算表名稱後面加一個$,例如預設的"Sheet1$"

--
參考資料
轉錄 C# 讀取 Excel
C# 讀取 Excel
DataTable 類別

在C#中讀取Excel的試算表名稱

在將Excel的檔案當做資料庫的存取的時候
可以先取得檔案中每個試算表的名稱,再做處理

public List LoadExcelSheetNameList(
string excelFile)
{
List sheetNameList = new List();

/// load excel file as an ole database
OleDbConnection excelDatabase =
new OleDbConnection(string.Format(
"Provider = Microsoft.Jet.OLEDB.4.0;" +
"Data Source = {0};" +
"Extended Properties='Excel 8.0;HDR=No'",
excelFile));
excelDatabase.Open();

/// load excel sheet as DataRow
DataRow[] sheetList =
excelDatabase.GetSchema("Tables").Select();
foreach (DataRow sheet in sheetList)
{
/// query each sheet name from excel file
sheetNameList.Add(
sheet["TABLE_NAME"] as string);
}

/// close and release database connection
excelDatabase.Close();

return sheetNameList;
}

在得到名稱後,就可以針對單一的試算表進行讀取

--
參考資料
[工作] 取得Excel頁籤名稱
如何取得 Excel 中的 Sheet Name

2010年12月27日 星期一

在C#中使用SQLite資料庫

自己開發程式的時候,想用資料庫又不希望花一大筆錢
常常會使用SQLite,一個輕量級的嵌入式資料庫系統(僅單一檔案)
由於.net原生並不支援SQLite
可以去System.Data.SQLite找到在公開的函式庫
注意如果是x64的程式,則需要使用x64版本的函式庫,無法混用

在每次使用資料庫的時候,都需要建立與相關資料庫的連結

private SQLiteConnection ConnectDatabase()
{
string path = "Test.db";
string password = "Password";
SQLiteConnection connection;

if (!File.Exists(_databasePath))
{
/// for non-exist database, create it
SQLiteConnection.CreateFile(path);
connection = new SQLiteConnection(
"Data Source = " + path);
connection.Open();
connection.ChangePassword(password);
}
else
{
/// for exist database, connect it
connection = new SQLiteConnection(
"Data Source = " + path);
connection.SetPassword(password);
connection.Open();
}

return connection;
}

這邊要注意的是,由於SQLite本身並沒有支援資料庫加密
有關Password的功能(紅字部分)是System.Data.SQLite實做的
所以製作出來的加密資料庫並不能被其他的SQLite應用讀取
(例如Firefox的附加元件SQLite Manager)
所以如果不打算加密,建議將紅字部分拿掉

在連結之後,就可以透過該連結,執行SQL的命令

private void RunCommand(
SQLiteConnection connection, string commandText)
{
SQLiteCommand command =
new SQLiteCommand(connection);
command.CommandText = commandText;
command.ExecuteNonQuery();
}

除了不需要回傳值的命令(例如CREATE TABLE)以外
SQL最重要的當然是Query的指令

private List RunQueryCommand(
SQLiteConnection connection, string commandText)
{
List<string> result = new List<string>();

SQLiteCommand command =
new SQLiteCommand(connection);
command.CommandText = commandText;

using (SQLiteDataReader queryResult =
command.ExecuteReader())
{
/// read one row one time
while (queryResult.Read())
{
/// change index to get different column
result.Add(queryResult.GetValue(0)
.ToString());
}
}

return result;
}

當然,在使用完畢後一定要記得將連結中止,否則資料庫檔案會被鎖住

private void DisconnectDatabase(
SQLiteConnection connection)
{
connection.Close();
}

另外,讀取資料庫的時候,如果不能肯定資料表是否存在
則需要先做一個檢查,否則會跳出例外狀況
(當然也是可以直接用try catch將Command包住,端看習慣)

private bool IsTableExist(
SQLiteConnection connection, string name)
{
return connection.GetSchema("Tables")
.Select("Table_Name = '" + name + "'")
.Length > 0;
}

--
參考資料
SQLite 簡介
System.Data.SQLite
C sharp or .Net 使用sqlite 設定
SQLite Manager
SQL語法教學
Check if table exists

Windows的顯示/隱藏桌面

在Windows XP預設的快速啟動列中會有一個捷徑,可以顯示/隱藏桌面
(隱藏/顯示所有已經開啟的視窗)
在XP的時候有時候會不小心砍掉(Win7中已經被放在視窗的右下角,反正也移除不掉,就不會有這個困擾),這時候可以自己重新做一個捷徑

先開一個純文字檔,內容如下

[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop

並將檔案附檔名改為.scf(檔名倒是無所謂,一般習慣設成"ShowDesktop.scf"或"顯示桌面.scf")就可以了

如果想要在程式中做出同樣的功能,則可以呼叫Shell.Application去呼叫ToggleDesktop這個命令

void ShowDesktop()
{
Type shell =
Type.GetTypeFromProgID("Shell.Application");
shell.InvokeMember("ToggleDesktop",
BindingFlags.InvokeMethod, null,
Activator.CreateInstance(shell), null);
}

--
參考資料
How to re-create the Show desktop icon on the Quick Launch toolbar in Windows XP
C#使用系統的「顯示桌面」功能(Shell.Application)

2010年12月21日 星期二

在WPF中發出鍵盤事件

WPF沒有控制鍵盤的API
所以要發出鍵盤事件(例如按下"J")就必須要呼叫Win32的API了

private enum KeyEventFlag
{
KEYEVENTF_KEYDOWN = 0x0000,
KEYEVENTF_EXTENDEDKEY = 0x0001,
KEYEVENTF_KEYUP = 0x0002,
}

[DllImport("user32.dll", SetLastError = true)]
private static extern void keybd_event(
byte bVk, byte bScan, KeyEventFlag dwFlags,
IntPtr dwExtraInfo);

這時發生一個問題,bVk是以Win32中定義的Virtual-Key Codes做為對照
但是在WPF中所採用的是Key 列舉型別
需要使用KeyInterop做轉換,所以實際上發出按下鍵盤的函式如下

private void SendKeyDown(Key key)
{
keybd_event(
(byte)KeyInterop.VirtualKeyFromKey(key), 0,
KeyEventFlag.KEYEVENTF_KEYDOWN, IntPtr.Zero);
}

另外,如果要送出放開鍵盤的事件,那就把KEYEVENTF_KEYDOWN換成KEYEVENTF_KEYUP,而連續送出一個按下加上一個放開,就變成Click了
同理,要發出復合鍵則是再放開前按下所有鍵,再放開即可

--
參考資料
.NET - How can I convert 'System.Windows.Input.Key' to 'System.Windows.Forms.Keys'?