2014年6月10日 星期二

[C#] 利用 BackgroundWorker 實作 multi-thread

  最近筆者在開發 In-house 應用程式 (application) 時,需監聽某一個處理程序 (process) 是否結束。若將監聽的 while 迴圈寫在主程式,將導致主程式會 HANG 在那裡。經由與同事討論後,發現必須將監聽的程式碼另外執行於新的執行緒 (thread) 上,方可避免主程式 HANG 住的問題。

  一開始,筆者使用 Thread。此方法雖可將監聽的部分另起,但若此執行緒已運行完畢,並無法通知主程式「我」已經結束。經由 google,發現可利用 BackgroundWorker 類別解決上述問題。下面為實作面的紀錄:

首先,必須載入 (import)

System.ComponentModel;

接著,於主程式中宣告物件 (object)

BackgroundWorker bw = new BackgroundWorker();

對物件 bw 進行設定

bw.DoWork += new DoWorkEventHandler(DoWork);
bw.RunWorkerCompletedEventHandler += new RunWorkerCompletedEventHandler(RunWorkerCompleted);


實作 Event Handle 函式

DoWork(object sender, DoWorkEventArgs e)
{
    // 於背景啟動此執行緒時的工作
}

RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // 當此執行緒運行完畢時的工作
}




  當然,解決方案不僅僅如此一種。只不過,這是我實際成功的方式,藉由部落格與各位分享!如有更佳的解決方案,歡迎提出討論。

參考資料:MSDN

2014年5月22日 星期四

[C#] 取得執行檔 (*.exe) 的圖標 (.ico) 【Get executable file's icon】

筆者最近最常開發的功能即為獲取執行檔的圖標,在此紀錄兩種不同的做法。

方法一:使用 SHGetFileInfo

using System.Runtime.InteropServices;

[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct SHFILEINFO
{
    public IntPtr hIcon;
    public int iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByvalTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByvalTStr, SizeConst = 80)]
    public string szTypeName;
};

public const uint SHGFI_ICON = 0x100;
public const uint SHGFI_LARGEICON = 0x0; // Large icon
public const uint SHGFI_SMALLICON = 0x1; // Small icon

IntPtr hImgSmall;
IntPtr hImgLarge;
SHFILEINFO shinfo = new SHFILEINFO();

public System.Drawing.Icon GetExeFileIcon(string exeFilePath)
{
    // Use this to get small icon
    hImgSmall = SHGetFileInfo(exeFilePath, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON |  SHGFI_SMALLICON);

    // Use this to get large icon
    hImgLarge = SHGetFileInfo(exeFilePath, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON |  SHGFI_LARGEICON);

    System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);

    return myIcon;
}


方法二:使用 Icon 類別 (System.Drawing)

using System.Drawing;

Icon myIcon = null;

public Icon GetExeFileIcon(string exeFilePath)
{
    myIcon = Icon.ExetractAssociatedIcon(exeFilePath);

    return myIcon;
}

2014年5月14日 星期三

[C#] Get Windows shortcut's target path

筆者最近在開發 In-house Windows application 的其中一項功能

──抓取使用者電腦中已安裝的應用程式的開發公司名稱 (Company Name)

遇到了一個問題:

「如果擷取的檔案為捷徑檔 (.lnk),那麼將無法獲得 Company Name;但是,如果擷取的檔案為執行檔 (.exe),將可獲得 Company Name」

經筆者觀察,執行檔的捷徑檔 (.lnk) 中的目標皆指向此捷徑檔相對應的執行檔路徑。因此,藉由抓取捷徑檔 (.lnk) 的目標並將之投入 FileVersionInfo 類別即可獲得此捷徑檔 (.lnk) 的 Company Name,請參考下圖:


範例程式碼如下:

首先,必須在 C# 專案中加入參考 (Reference) IWshRuntimeLibrary

using IWshRuntimeLibrary;

public string GetLNKTargetPath(string LNKFilePath)
{
    // Input LNKFilePath: Your LNK file's absolute path.
    WshShell shell = new WshShell();
    IWshSortcut shortcut =

        (IWshSortcut)shell.CreateShortcut(LNKFilePath);
    return shortcut.TargetPath; // Your LNK file's target path.
}

2014年5月7日 星期三

[C#] 新增、刪除、取得 Windows 系統登錄檔 (Registry)

  在 Windows programming 中,經常會利用系統登錄檔 (Registry) 儲存應用程式 (Application) 相關組態 (Configuration) 等資訊。以下文章將示範如何使用 C# 進行系統登錄檔 (Registry) 的新增、刪除和修改。

在 C# 中對系統登錄檔 (Registry) 操作必須先載入相關 namespace:

using Microsoft.Win32;

接下來將以 Current User 下的 SOFTWARE 為例,進行操作的講解。

新增
string registryPath = @"SOFTWARE"; //HKEY_CURRENT_USER\Software
//開啟 Software 子系統登錄檔
RegistryKey regKey = Registry.CurrentUser.OpenSubKey(registryPath);
regKey.SetValue(registryName, registryValue); //建立 Name/Value
regKey.close();


刪除
string registryPath = @"SOFTWARE"; //HKEY_CURRENT_USER\Software
//開啟 Software 子系統登錄檔
RegistryKey regKey = Registry.CurrentUser.OpenSubKey(registryPath);
regKey.DeleteValue(registryName); //刪除 registryName
regKey.close();


取得
string registryPath = @"SOFTWARE"; //HKEY_CURRENT_USER\Software
//開啟 Software 子系統登錄檔
RegistryKey regKey = Registry.CurrentUser.OpenSubKey(registryPath);
regKey.GetValue(registryName); //取得 registryName
regKey.close();




參考資料:MSDN

2014年3月10日 星期一

[Ubuntu, Git, GitHub] 在 Ubuntu 12.04 上使用 GitHub

最近看了些新聞以及求才訊息,發現不少公司都將 GitHub 視為工程師加分的一個條件。

在公司內,專案開發使用的版本控制系統為 Subversion

趁著撰寫軟體驗證 (Proof Of Concept) 的時候,將自己的程式碼上傳至並學習 GitHub。

筆者大多數的程式碼皆在 Ubuntu 上進行開發,故下列文章內容將以 Ubuntu 12.04 作為範例。

首先,GitHub 仍然是以 Git 為基礎的,所以必須在 Ubuntu 12.04 上安裝 Git

sudo apt-get install git

接下來,必須對 Git 進行配置 (configure)

git config --global user.name "Your GitHub Username"
git config --global user.email "Your GitHub 註冊 Email"

如果,今天你已經有現存的 repository,請先複製 (clone) 下來

git clone https://github.com/Your GitHub Username/Your Repository Name.git

接著,可在您複製的資料夾內進行專案管理。

如果您新增了一份檔案,最終您必須將檔案新增至 repository。

git add Your New File

新增完畢,將檔案 commit 至 repository

git commit -m 'Your commit message'

最後,將您修改的檔案 push 回 GitHub

git remote add origin https://github.com/Your GitHub Username/Your Repository Name.git

git push origin master ( 輸入您的帳號與密碼 )

完成上述流程,一切就大功告成囉!

2014年1月27日 星期一

[Python, Socket] Error Code: 98 Message Address Already in Use

最近在開發一些 Proof of Concept 的程式,使用到 Python 的 socket。

Socket server / client 的開發上並未遇到太大的問題,倒是後續的使用上時常遇上

Bind failed. Error Code: 98 Message Address already in use 這問題。

經過 Google 大神的指示,小弟透過這裡紀錄解決方法,以便後續查找!

問題發生的主因,似乎是 socket server 在 listen 的 port 被占住了!導致系統回報錯誤。

首先使用

sudo netstat -ltnp | grep ':YOUR PORT NUMBER'

上述的指令會回覆:

tcp   0   0 0.0.0.0:YOUR PORT NUMBER   0.0.0.0:*   LISTEN   30381/python

由此回覆,我們發現 YOUR PORT NUMBER 正使用 process 30381 ( 表示使用中 )

這時候把這一個 process kill 掉就可以解決問題囉!

sudo kill -9 30381

2014年1月22日 星期三

[Android] 如何改變 application 啟動的第一個 Activity (How to change app's starting activity?)

先前在開發 Android 的時候,遇上了一個很囧的問題。

就是新開發的 activity ( 不是新創專案就有的那個 activity ),

希望將它視為 application 一啟動後就載入的第一個 activity。

當然,遇到問題的第一步就是‧‧‧詢問 Google 大神囉!

找到的詳解為:

在專案的 AndroidManifest.xml 檔案中,將您預想 launch 的那一個 activity 修正為

<activity android:name=".Your app's starting activity"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />                 </intent-filter>
</activity>


參考資料:http://ppt.cc/OpKg