2009年5月19日 星期二

如何隱藏win32 console application的console視窗

此種方法是利用設定編譯器的鏈結開關來實現, 所以讓我們來看一下Linker選項, 如下圖所示



這個Linker選項是告訴作業系統如何運作執行檔,
如果我們建立一個Win32 console application的話,
Linker/subsystem選項應該為Console.

我們知道用VC編寫的程式, 執行的時候是需要 C\C++執行庫支援的.
當我們執行一個C/C++程式的時候, 鏈結器會首先尋找應用程式的啟動函數.


如果你建立了一個console程式的話, Linker的鏈結開關會是下面這種形式
/subsystem:"console" /entry:"mainCRTStartup" (ANSI)
/subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)


在default情況下/subsystem/entry開關是對應的,也就是:
console 對應 mainCRTStartupwmainCRTStartup
windows 對應 WinMain或者wWinMain

但是我們也可以通過手動的方式使他們不對應,
在default情況下Linker看到/subsystem下是windows選項的時候,
它會自動尋找WinMain或者wWinMain, 但我們強制指定入口位址,
這樣執行程式的時候console視窗就會隱藏!

如下面程式碼所示:

#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 設置入口位址
int main(int argc, char* argv[])

{

return 0;
}

參考網址: http://forum.icst.org.tw/phpbb/viewtopic.php?f=44&t=7609&start=0

取得目前螢幕解析度

#include "windows.h"

int ScreenHeight, ScreenWidth;
ScreenHeight = GetSystemMetrics(SM_CYSCREEN); //取得高度的像素
ScreenWidth = GetSystemMetrics(SM_CXSCREEN); //取得寬度的像素

各參數的定義, 可參考此網頁 : http://tech.ddvip.com/2008-11/122655593392184.html

2009年5月17日 星期日

防止程序重複啟動的方法

主要使用到CreateMutex()函數和GetLastError()以及一個常量ERROR_ALREADY_EXISTS.


CreateMutex()函數可用來創建一個有名或無名的互斥量對象,其函數原型為:

HANDLE CreateMutex
(

LPSECURITY_ATTRIBUTES lpMutexAttributes, //指向安全屬性的pointer

BOOL bInitialOwner, //初始化互斥對象的所有者
LPCTSTR lpName //指向互斥對象名字的pointer
);



如果函數執行成功,將return一個互斥量對象的handle。 如果在CreateMutex()執行前已經存在有相同名字的互斥量,函數將返回這個已經存在互斥量的handle,並且可以利用GetLastError()得到錯誤代碼ERROR_ALREADY_EXIST可見,利用對錯誤代碼ERROR_ALREADY_EXIST的檢測可以實現CreateMutex()對程序的互斥。

下面為sample code:
HANDLE ManagerMutex = CreateMutex(NULL, FALSE, _T("OTM_Manager.exe"));

if (GetLastError( ) == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, _T("OTM_Manager is already running"), _T("Warning!"), MB_OK);
CloseHandle(ManagerMutex );

PostQuitMessage(0);
return FALSE;
}

2009年5月15日 星期五

什麼是DLL?

DLL 是動態連結程式庫, DLL提供一種方法,讓處理序 (Process) 呼叫不是可執行程式碼部分的函式。函式的可執行程式碼位於 DLL 裡,它包含一或多個已編譯、連結的函式,並且儲存在與使用它們的處理序不同的地方。 例如, 我們開發的Canvas, Gesture Handler, Rubik's Cube...等一些應用程式, 都會利用OTMUT.dll來開發Touch/Gesture的相關功能。 這有助於提升程式碼重複使用及有效率的記憶體使用量。

應用程式和 DLL 之間的差異?
雖然 DLL 和應用程式都是可執行程式模組, 但是它們在許多方面卻是不同。對使用者而言,最明顯的差異在於 DLL 不是可以直接執行的程式. 從系統觀點來看,應用程式和 DLL 之間有兩個基本差異:
  • 應用程式本身可以同時在系統中執行多個執行個體,而 DLL 只能有一個執行個體。
  • 應用程式可以擁有如堆疊、全域記憶體、檔案控制代碼 (File Handle) 和訊息佇列等,而 DLL 則不含這些
動態連結與靜態連結的差異?

動態連結(Dynamic Link Libraries)允許可執行模組 (.DLL 或 .EXE 檔) 只包含在執行階段時用來找出 DLL 函式可執行程式碼的所需資訊。
在靜態連結(Static-Link Libraries)中,連結器 (Linker) 會從靜態連結程式庫取得所有參考函式,並且將它與您的程式碼一起放入可執行檔,它的內容除了程式設計者所設計的程式碼之外,還包含了所使用程式庫的程式碼,所以其檔案變得相當大。

使用DLL的優點:
  • 使用較少的Resources
    當多個程式使用相同的Library時, DLL 可以減少重複的程式碼, 並且在執行時期需要時才載入, 這樣可以提升執行的效能。

  • 模組化結構升級
    DLL 有助於提升開發模組化的程式。 這可協助您開發大型的程式需要有多個語言版本或需要模組化結構的程式, 可降低應用程式的複雜度,程式更新維護時較方便。

  • 簡化Deployment Installation
    當函式在 DLL 內需要的更新程式或修正程式, 只要函式的引數和傳回值沒有改變,使用這些函式的應用程式就不需要重新編譯或重新連結。這樣的例子, 常發生在dll 要給 third-party應用程式來使用, 而library需要經常update或fix

Debug的好工具: DebugView

DebugView 是一種應用程式,可讓您針對本機系統或是網路上可以透過 TCP/IP 連線的任何電腦,進行偵錯輸出的監視。它可以同時顯示核心模式和 Win32 偵錯輸出,因此不需要使用偵錯工具來擷取應用程式或裝置驅動程式所產生的偵錯輸出,也不需要將應用程式或驅動程式修改成使用非標準的偵錯輸出 API。

DebugView 具有大量功能強大的功能,可控制和管理偵錯輸出。
以下是部分 DebugView 其他功能的清單:
  • 遠端監視:從任何可透過 TCP/IP (甚至透過網際網路) 存取的電腦,擷取核心模式和 (或) Win32 偵錯輸出。您可以同時監視多部遠端電腦。如果您是在 Windows NT/2K 系統上執行 DebugView,而且是從相同 [網路上的芳鄰] 的另一個 Windows NT/2K 系統進行截取,DebugView 甚至會自行安裝它的用戶端軟體。
  • 最近篩選清單:DebugView 會記住您最近的篩選選擇,且具有可讓您輕鬆重新選取它們的介面。
  • 處理程序識別碼選項切換 Win32 偵錯輸出之處理程序識別碼的顯示。
  • 剪貼簿複製:選取輸出視窗中的數行,並將它們的內容複製至剪貼簿。
  • 記錄至檔案:在擷取偵錯輸出的同時將它寫入至檔案。
  • 列印:將所有或部分擷取的偵錯輸出列印至印表機。
  • 單一檔案承載:DebugView 是以單一檔案實作。
  • 損毀傾印支援:DebugView 可以從損毀傾印復原它的緩衝區,並將輸出儲存至記錄檔,這樣使用者就可以將 NT 驅動程式到損毀為止之前產生的輸出傳送給您。

安裝和使用

1. 下載DebugView
http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx


2. 執行DbgView.exe
下載完成之後,解開壓縮檔會有一個檔案 DbgView.exe (檔案 DbgView.chm也有使用說明),執行此執行檔就會看到一個 DebugView 視窗



3. 利用OutputDebugString作trace
在你 VC 的 Project 中加入OutputDebugString的程式碼(看要加在哪裡,自己決定,主要是你想在 runtime 期間,顯示出來的訊息)
Ex: OutputDebugString(_T("OTMUT.dll: Fail to execute OTM_Manager.exe"));

DebugView 的界面很簡捷方便,它還提供FilterHighlight功能.因為所有的程序都可以用OutputDebugString輸出,當然因該 filter掉那些你不關心的程序的trace。有時候你想要讓關鍵Trace顯眼一點,可以highlight包含指定字符串的Trace。

2009年5月14日 星期四

Debug 和 Release的不同

有時候我們執行程式時會遇到Debug版可以跑,但是Release版本反而不能跑了,為什麼呢?
首先, 先了解DebugRelease的主要差異:

Debug版:包含Microsoft格式的除錯資訊,沒有進行最佳化,檔案體積較大
Release版:不包含除錯資訊,有針對執行速度最佳化,檔案體積較小

事實上Debug Release 並沒有本質的界限,他們只是一組編譯選項的集合,編譯器只是按照預定的選項行動.

Debug各參數的定義:
Release各參數的定義:


那些情況下Release版的程式會出錯?
  • Runtime Library差異(MDd和MD)
  Runtime Library 包含了除錯用的訊息,並採用了一些保護機制以幫助發現錯誤,所以性能上較不如Release的版本。編譯器提供的 Runtime Library通常很穩定不會造成 Release 版本錯誤;倒是由於 Debug Runtime Library 加強了對錯誤的檢測,如Heap的記憶體分配,有時會出現Debug 有錯但 Release 正常的現象。這裡要注意的是,如果 Debug 有錯,即使 Release 正常,程式保證是有 Bug 的,只不過可能是 Release 版的某次執行沒有表現出來而已。

  • 最佳化的影響(O1和O2)
  在函式的呼叫過程中,所有呼叫的訊息(回傳位址、參數)以及自動變數都是放在堆疊中的。如果函式的宣告跟實作不同(參數、回傳值、呼叫方式),就會產生錯誤,但 Debug 方式下,堆疊的存取透過 EBP 暫存器儲存的位址來實現,如果沒有發生陣列越界之類的錯誤(或是越界「不多」),函式通常能正常執行;Release 方式下,最佳化會省略 EBP 堆疊基本位址的指標,這樣通過一個全域指標存取堆疊,可能就會造成回傳位址錯誤導致整個程式崩潰。

  當您建置專案進行偵錯時,您是使用偵錯記憶體配置器 (Debug Memory Allocator)。這表示所有的記憶體配置周圍都放置了保護位元組。這些保護位元組會偵測記憶體覆寫。由於Release的組建與Debug版的堆積配置不同,在Debug中的記憶體覆寫可能不會造成任何問題,但在Release的組建中卻可能產生災難性的影響。
  • 變數的初始化(GZ的選項)
  Deug通常會將記憶體和變數做初始化,包括用 0xCC 初始化所有自動變數,0xCD(Cleared Data)初始化Heap中分配的記憶體(即動態分配的記憶體,例如 new ),0xDD ( Dead Data ) 填充已被釋放的Heap記憶體(例如delete),0xFD(deFencde Data)初始化受保護的記憶體(debug 版在動態分配記憶體的前後加入保護記憶體以防止越界存取).

  Release 版中未初始化的變量是隨機的(沒有初始化),這有可能使指針指向一個有效地址而掩蓋了非法訪問.

  • DEBUG 與 NDEBUG
  當定義了 _DEBUG 時,ASSERT() 函式會被編譯,而 NDEBUG 時不被編譯。此外,TRACE() 巨集的編譯也受 _DEBUG 控制有些人會自行定義#ifdef _DEBUG 之類的條件編譯,必須注意。


解決Release 版出錯的問題
  • 逐項測試Release的編譯選項
  前面已經提過,DebugRelease只是一組編譯選項的差別,實際上並沒有什麼定義能區分二者。我們可以修改Release版的編譯選項來縮小錯誤範圍。如上所述,可以把Release 的選項逐個改為與之相對的Debug選項,如/MD改為/MDd、/O1改為/Od,或運行時間最佳化改為程序大小最佳化。 注意,一次只改一個選項,看改哪個選項時錯誤消失,再對應該選項相關的錯誤,針對性地查找。
  • 對變數作初始化
  • 檢查ASSERT(),TRANCE()和#ifdef _DEBUG 之類的條件編譯的使用
  • 注意VC的警告訊息
  在 Debug 版中使用 /W4 警告級別,這樣可以從編譯器獲得最大限度的錯誤訊息,比如 if( i =0 )就會引起 /W4 警告。不要忽略這些警告,通常這是你程式中的 Bug 引起的。但有時 /W4 會帶來很多冗長的訊息。我們可以用:

   #progma warning(disable: 4702) //禁止
   //…
   #progma warning(default: 4702)
   //重新允許來暫時禁止某個警告,或使用

   #progma warning(push, 3) //設置警告級別為 /W3
   //…
   #progma warning(pop) //重設為 /W4
   //暫時改變警告級別,有時你可以只在認為可疑的那一部分程式碼使用
  • Dll的使用
  將其他不同版本的Dll混合造成不一致的現象稱為“動態連結庫的地獄(Dll Hell)”
  http://www.codeproject.com/dll/The_DLL_Hell.asp
  http://www.developerfusion.co.uk/show/1719/9/

  如果你的程式使用DLL時請注意,不能將debugrelease版的DLL混合在一起使用。
  • 利用Debug工具
   DebugView : 可用來捕捉OutputDebugString(),可以在VC的環境外執行程式查看除錯訊息.
   Gimpel Lint :靜態代碼檢查工具,不過要花$.
   SmartChecker: Rum-Time錯誤檢查工具
   BoundsChecker: Rum-Time錯誤檢查工具



My first blog

其實在我心中, 早就想寫這樣的部落格,
但實在是, 我有點太懶, 每次都只是在心中想, 卻都沒付諸行動,
終於在我們老大的鼓舞下, 開始了我的第一步.
在這blog上, 我會把coding或工作上, 遇到的一些問題, 或學到一些知識分享出來.
畢竟現在的人, 解決問題的方式, 不外乎是透過網路搜尋,
希望在這裡大家能找到想要的東西, 或是交流你們的想法.