2008年12月30日 星期二

[Inno Setup] 如何讓程式在windows啟動後自動執行

有兩種做法,一種是直接將捷徑放在"Start Menu"的"啟動目錄"裡

[Icons]
Name: "{commonstartup}\yourapp"; Filename: "{app}\yourapp.exe"; WorkingDir: {app};
Name: "{userstartup}\yourapp"; Filename: "{app}\yourapp.exe"; WorkingDir: {app};

{commonstartup}是放在共用的"啟動目錄",所有使用者共用這一個捷徑。
{userstartup}則是放在該user的"啟動目錄"。

另一種做法是寫registry

[Registry]
Root: HKCU; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "yourapp"; ValueData: "{app}\yourapp.exe"; Flags: uninsdeletevalue;


上面兩種方法都可以讓你的程式在每次啟動windows時自動執行。

2008年12月19日 星期五

[Inno Setup]檢查程式是否已安裝,並且詢問user是否要安裝舊版程式

我有一個用COM寫的dll,因為會給很多支程式一起發佈,這種清況下有可能使用者剛好安裝到舊版本的dll,雖然這樣不是什麼大問題,但是我還是希望使用者盡量使用最新的dll(不安裝舊版程式),因此我在Inno Setup加入一小段pascal code去解決這個問題。


[Setup]
; your setup setting

[Code]
function InitializeSetup(): Boolean;
var version: String;
begin
result := true;
if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\yourapp', 'DisplayVersion', version) = true then begin
if CompareStr(version, '1.1.5.0') > 0 then ; 1.1.5.0是你最新版的version
if WizardSilent() = false then begin ; Silent就預設不安裝舊的
if MsgBox('Would you like to install the older version?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDNO then begin ;詢問user
result := false;
end;
end else begin
result := false;
end;
end;
end;


Note:
1. 原本是以為Inno Setup有這個選項可以設定,不過找了一下還是沒找到,所以就自己手動弄了.. XD

2008年12月18日 星期四

VC9 SP1 Hotfix For The vector> Crash

今天在Visual C++ Team Blog 看到 這一篇,官方有針對VC9 的SP1釋出一個修正檔,主要是根據這邊的bug list修正了底下5個問題

1. function<FT>::swap() was broken by the Small Functor Optimization in VC9 TR1 (the Feature Pack). This broke vector<function<FT>> in VC9 SP1. "Broken" meant "compiling but crashing".

2. vector<pair<X, string>> nonconformantly required X to have a default constructor. (This is a specific example of a general bug: vector<pair<string, X>>, vector<pair<X, vector<int>>>, etc. were also affected.)

3. vector<tuple<X, Y, string>> nonconformantly required X and Y to have default constructors. (This is a specific example of a general bug, see above.)

4. vector<array<X, N>> nonconformantly required X to have a default constructor.

5. Random distributions were broken, triggering infinite loops and emitting bogus results.

假如你有安裝VC9 sp1的話,可以更新一下 :)


References:

1. Visual C++ Team Blog

2. VC9 SP1 Hotfix For The vector> Crash

3. TR1 fixes in VC9 SP1

2008年12月16日 星期二

一個免費的安裝程式 - Inno Setup

如果你還在找一個適合的安裝程式 (ex: Visual C++ 、BCB的安裝程式),且不想用原本complier附的安裝程式的話,可以試試這一套「Inno Setup」,他是免費的,而且只需要寫一些簡單的script,我個人用起來還簡單好用的。(我有用過在Visual C++ 2005, 2008以及BCB6和WinCE的安裝)

底下我將比較常用的script列出來
[Setup]                           ; 設定頁面
AppName=MyApp ; 程式名稱
AppVerName= MyApp 2.0 ; 程式版本名稱
AppVersion=2.0.0.456 ; 版本
DefaultDirName={pf}\MyApp ; 安裝的預設目錄 {pf}是指Program Files
DefaultGroupName=MyApp ; 在「開始/程式集」的目錄
Compression=lzma ; 壓縮的方式
SolidCompression=yes ; 安裝程式是分佈多個檔案或是合併成一個檔案
OutputDir=..\..\bin\ ; 輸出安裝程式的目錄
OutputBaseFilename=MyApp 2.0.0 ; 輸出安裝程式的名稱

[Files] ; 你要發佈的檔案清單
; Source: 來源路徑
; DestDir: 目地目徑,{app}可能是DefaultDirName或user自訂
Source: MyApp.exe; DestDir: {app};
Source: MyApp.dll; DestDir: {app};
Source: help.txt; DestDir: {app}\help; Flags:

[Dirs] ; 要建立的目錄
; Name: 要建立的目錄路徑,其中{userappdata}是指user的My Documents目錄
Name: "{userappdata}\MyApp";

[Icons] ; 要建立的shortcut
; Name: shortcut的名稱,其中{group}可能是DefaultGroupName或user自訂
; Fileanme: shortcut要對映的名稱
; WorkingDir: shortcut的預設執行目錄 (這要記得加喔!)
Name: "{group}\MyApp"; Filename: "{app}\MyApp.exe"; WorkingDir: {app};

; {uninstallexe}是指uninstall的路徑
Name: "{group}\Uninstall"; Filename: "{uninstallexe}"; WorkingDir: {app};

[Run] ; 要執行的程式
; Filename: 程式名稱
; Description: 你的程式描述
; Flags:
; postinstall: 安裝程式後才會執行
; nowait: 安裝程式不會等待程式執行完畢,並且繼續下一步動作
Filename: "{app}\MyApp.exe"; Description: "Launch application"; Flags: postinstall nowait

更多設定項目請參考Inno Setup附的example或是help。
或是參考FAQKnowledge BaseMailing List


Inno Setup可以透過簡單的pascal語法來寫一些程式,例如自訂畫面、資源檢查或是檔案的操作,如果嫌Inno Setup的指令太少,那你可以外掛一些用C寫的dll來和pascal配合,來增加Inno Setup的指令及功能。
底下是一個簡單在Welcome的畫面時顯示MsgBox。

procedure CurPageChanged(CurPageID: Integer);
begin
if (CurPageID= wpWelcome) then begin
MsgBox('Welcome to Inno Setup.', mbInformation, MB_OK);
end;
end;


另外,網路上很多人為Inno Setup寫了一些額外的套件,可以直接使用UI來設定script或是增加#include來引用已寫好的script等功能,有興趣的可以下載Third-Party QuickStart Packs來玩玩。


結論:
Inno Setup是一個免費又簡單好用的安裝程式。 :)


下載 (Downloads):
1. Inno Setup Stable Release - 主程式
2. Third-Party QuickStart Packs - 包含常用的third-party元件

一些Inno Setup的技巧:
1. Inno Setup 包裝 Visual C++ runtime library
2. Inno Setup 如何在安裝程式前,先檢查並關閉之前的程式
3. more

Reference:
1. Inno Setup

2008年12月15日 星期一

Discovery廣告- 世界無比精采! Boom De Ah Dah



歌詞:
Astronaut1:It never gets old, uh?
太空人1:地球從不會變老,對吧?
Astronaut2:Nope.
太空人2:不。
Astronaut1:it kinda make you want to break into songs?
太空人1:真令人想高歌一曲不是嗎?
Astronaut2:Yep.
太空人2:就是啊。

I love the mountains
我愛高山。
I love the clear blue skies
我愛藍天
I love big bridges(建築奇觀)
我愛大橋
I love when great whites fly
我愛飛躍的大白鯊

I love the whole world
我愛全世界
and all its sights and sounds
我愛這個聲色世界

Boom De Yada(這邊好像是漁人的搏鬥)
Boom De Yada
Boom De Yada
Boom De Yada﹗

I love the ocean
我愛海洋
I love the dirty things(幹盡苦差事的主持人Mike Rowew)
我愛苦差事
I love to go fast
我愛速度感
I love Egyptian kings
我愛埃及法老王

I love the whole world
我愛全世界
and all its craziness
我愛這瘋狂的世界

Boom De Yada
Boom De Yada
Boom De Yada
Boom De Yada(新時代武器的Richard Machowicz)

I love tornado(追風日誌)
我愛龍捲風
I love arachnid(Bear Grylls荒野求生密技)
我愛蜘蛛
I love hot magma
我愛岩漿
I love the giant squids
我愛大章魚

I love the whole world
我愛全世界
it's such a brilliant place
這世界實在太讚

Boom De Yada(流言終結者的亞當和傑米)
Boom De Yada(霍金博士w)
Boom De Yadaaaaaaaa
Boom De Yada
Boom De Yada
Boom De Yada
Boom De Yada
Boom De Yada
Boom De Yada
Boom De Yada

2008年12月13日 星期六

base class的virtual destructor的補充

我是習慣讓base class有virtual destructor,因為大部分我都是需要做多型刪除(polymorphic deletion)的,主要觀念是從C++編程規範來的,我節錄一下書裡編號50的準則


令base class的解構式為public virtual或protected nonvirtual
摘要(Summary):
刪還是不刪,真讓人頭疼:如果允許透過pointer to Base來刪除物件,那麼Base的解構式必須是public virtual函式。否則它應該是protected nonvirtual函式。


意思指的是


客戶要不就應該透過pointer to Base進行多型刪除(polymorphic deletion),要不就不該刪除。


如果允許多型刪除的話,那解構子就應該是public且為virtual function。
反之若不希望客戶進行多型刪除的話,那解構子就設計為nonpublic且nonvirtual。


上述這種判斷方式會比「將所有base class都固定加入virtual dtor」來得好。 :)


例外狀況


你可以讓解構式是public且nonvirtual,但必須在文件中清楚說明:B的更深層衍生物件(further-derived objects)絕對不能被多型使用(當作B)。std::unary_function就是這樣。





Notes:
1. base class指的是那些"準備要被繼承的底層類別"。

2. 並不是要將所有class都加入virtual dtor,而是如果該class可能會被繼承且需要支援多型刪除的話,那就加入virtual dtor,反之,如果該class根本不會(或是不希望)被繼承的話,那就不需要加入virtual dtor。

3. virtual dtor常常可以用來識別class能否被繼承。

4. 至於像unary_function這種class,除了文件註明外,解構子可以考慮設計為protected。 (這個書上也有提到)

Reference:
1: C++編程規範 - 101個準則、指導方針,和最佳實踐 - 侯捷/陳碩 譯
2.
Re: ‘dynamic_cast’ : ‘A’ is not a polymorphic type - http://fsfoundry.org/codefreak/
3.
http://legnaleurc.blogspot.com/2008/11/2.html
4.
'dynamic_cast' : 'A' is not a polymorphic type


因為感覺這一篇寫得不夠完整且完整表達我的想法,因此我有稍微修改過。

2008年12月9日 星期二

Ultimate Toolbox原來已經是免費的了啊

最近工作上需要使用TreeCtrl做多選(Multi-Select)的操作,因為MFC的CTreeCtrl預設是不支援多選的,因此我試著在CodeProject或是CodeGuru找尋解答,以前一直都是直接套用別人改寫的元件,但是也因為該元件並非正式的,常常都是沒有文件而且缺少維護,存在著很多bug,而我其實也沒啥時間去解那些bug,後來想說來查一下Ultimate Toolbox這套商業元件目前的售價好了,再來跟我主管商量看看要不要撥經費來購買,後來發現Ultimate Toolbox, Grid, TCP/IP都已經變成免費而且open source的了,以前小時候(咦?)的印象他是商業套件而且是需要錢的啊,怎麼會突然變免費的呢(2007年8月開始open source的),後來上網查了一下,我猜想可能是因為他的另一對手BCGSoft和微軟合作的關系,並且在Visual C++ 2008 Feature Pack加入大量且免費的BCGSoft元件,因此逼得使Ultimate Toolbox也必須改變策略而選擇open source一途吧。

也正好,Ultimate Toolbox剛好有我需要的TreeCtrl,而且比我現在使用的網路免費的元件還強得多很多,真是謝天謝地啊 XD

後記
其實Visual Studio 2008 Service Pack 1(包含Visual C++ 2008 Feature Pack)裡加入了大量的BCG元件(MFC Hierarchy Chart),用起來方便很多,不再需要為GUI來煩惱,也不太需要上網四處搜尋元件了,可以專注在更核心的問題。
不過,為什麼還是沒有高階(完整)的TreeCtrl呢?? =.=.. 我只是要做一個Multi-Select而已啊
結果還要花時間再找解決方案以及編譯Ultimate Toolbox.. orz


ps. 我還真是後知後覺。

2008年12月7日 星期日

C++的列舉型別的type-safe問題 (2)

繼上一篇「C++的列舉型別的type-safe問題」,其實基本上我會找到bitwise這個enum class template是因為我需要enum的bitwise operations,因為C++原本的eums的bitwise operations有一些type-safe上的問題,以及缺少一些bitwsie operations。


enum Style
{
StyleA = 0x01,
StyleB = 0x02,
StyleC = 0x04,
}

enums Area
{
Area1,
Area2,
Area3,
Area4,
}

// pass
Style s1 = StyleA;

// error, can't convert int to enums 'Style'
s1 = StyleA | StyleB;


很神奇的,為什麼StyleA | StyleB的結果無法放在s1裡呢,因為StyleA | StyleB的結果會是一個int而不是enum 'Style'。主要原因應該還是因為C++裡並沒有Enum operator |(Enum s1, Enum s2),而會implicit將enum轉成int,而改呼叫int operator (int s1, int s2),所以回傳值會是個int而不是enums囉。但是這不是我們預期的結果。

下面這樣的強制轉型可以解決上面的問題

// ok
Style s1 = static_cast<Style>(StyleA | Style B);


但是如果你不小心打錯了呢?

// pass, but what is 'StyleA' | 'Area4'??
Style s1 = static_cast<Style>(Style | Area4);

這樣的強制轉型方式缺乏type-safe。

另外如果你需要Enum Enum::operator |=(Enum s2) 這種運算的話,那現有的C++是不支援的喔

// error, no |=, &= operation in enums
s1 |= StyleC;
s1 &= StyleC;


所以很自然的你會改成下面這樣

// error, can't conver int to enums 'Style'
s1 = s1 | StyleC;
s1 = s1 & StyleC;


咦~ 又不對.. XD,因為跟之前的問題一樣,你需要做強制轉型將int轉成enum,所以在做bitwise operations會常常需要強制轉型。


function的參數也是一樣會遇到要強制轉型的問題

void foo(Style style)
{
// ...
}

void main()
{
/ error, can't conver int to enums 'Style'
foo(StyleA | Style B);

// pass, but it's non type-safe
foo(static_cast<Style>(StyleA | StyelB));
}


所以會看到有些lib的function的參數就不使用enum,改成unsigned int這種整數型態。

void foo(unsigned int style)
{
// ...
}

void main()
{
// pass, but it's non type-safe
foo(StyleA | Style B);
}


假設你改用bitwise_enum這個template class的話,除了上一篇講到的功能,當你在bitwise operations時依舊可以做到type-safe。

#include "bitwise_enums.hpp"

void foo(bitwise_enum<Style> style)
{
// ...
}

void main()
{
// pass
bitwise_enum<Style> s1 = StyleA | StyleB;
s1 |= StyleC;
foo(StyleA | StyleB);

// error, your complier will say it can't convert enums 'Area' to 'Style', :)
foo(StyleA | Area1);
}



不過用bitwise_enum有一些缺點,因為bitwise_enum有implict ctor自動將enum轉成bitwise_enum,因此當你要判斷某個bit是否為1時,你不能用簡單的 and 運算,而需要呼叫他的member function。

bitwise_enum<Style> s1 = StyleA | StyleB;
if (s1.has_bits(StyleC)
{
// ...
}


Note:
1. 跟前一篇一樣,如果我們不去擔心type-safe的問題的話,那用強制轉型這樣其實也沒什麼問題的。

Reference:
1. bitwise_enums
2. bitwise_enums ComplierErrors

C++的列舉型別的type-safe問題

C++的enums(列舉型別)相當實用,特別是和#define, const int比起來
1. 型別檢查 (type-safe),這是#define, const做不到的。
2. 將相關的type放在別一個enums,不會像#define, const 定義的常數一樣,沒有group的概念。


enum Style
{
StyleA,
StyleB,
StyleC,
}

enum Area
{
Area1,
Area2,
Area3,
Area4,
}

// pass
Style s1 = StyleA;

// error, can't convert from int to enums 'Style'
s1 = 2;

// error, can't convert from enums 'Area' to 'Sytle'
s1 = Area3;

// pass, if you really need do it (it's non type-safe)
s1 = (Style)10;
s1 = (Sytle)Area4;

// ok, but it's non type-safe
int s2 = Area1;
s2 = Style1;


enums可以幫你在assignment operation時做型別檢查,避免你在寫程式時指定錯誤的type到enums裡,但是enums也不是所有的型別檢查都會做,考慮以下的清況:

Style s1 = Style1;

// pass and the complier will not say any errors
if (s1 == Area1)
{
// ...
}

為什麼會這樣呢,我想是C++因為沒有Implement operator==(Enum s1, Enum s2)的關係,且Enum可以implicit轉型為int,因此實際上呼叫的是operator==(int s1, int s2)的運算,這樣的結果會造成在enums的equal operation時缺少type-safe,而我認為type-safe對一個常常要mantain多個程式的programmer來說是非常重要的(其實即使只寫一個簡單的程式,我還是希望complier會幫我做type-safe XD),我之前就是碰到類似的問題,我拿別的enums來和我正在使用的enums來比較,並且complier也過了,因此我認為我的程式碼沒有問題了,如果有問題的話我的complier"應該"會告訴我才對,很不辛的,這個問題造成我的程式在客戶端才被發現錯誤(黑箱測試時並沒有測出這個bug orz),而且是在release數個月之後才由user發現的,這所花的成本我想遠比改寫程式為type-safe還花得高,因此後來我也慎重的告誡我們公司的程式設計師,這個type-safe的重要性。

那要怎麼解決這個問題呢,網路上有人寫了一個enums template class來包裝enums,他提供operator==(Enum s1, Enum s2)的運算,並且增加多個enums的bitwise運算(這個下一篇文章再提好了),強化我們的complier的錯誤檢查能力,並提升type-safe。

我使用的是這一個bitwise_enum class
google code的網址是:http://code.google.com/p/bitwise-enum/
目前的版本是1.2版 (http://bitwise-enum.googlecode.com/files/bitwise_enum-1.2.tgz)

#include "bitwise_enums.hpp"

// pass
bitwise_enums s1 = Style1;

// pass
s1 = Style2;

// pass
if (s1 == Style2)
{
// ...
}

// error, your complier will say it can't convert enums 'Area' to 'Style' for equal operation
if (s1 == Area1)
{
// ...
}


Notes:
1.
如果你打算使用bitwise_enums取代現有的寫法的話,因為bitwise_enum用了一些隱喻轉換的constrctor以及non-member operation function,可能會造成你現有的程式碼錯誤,如果要避開這個問題的話,可以將bitwise_enums用namespace包起來。


namesapce utils
{
#include "bitwise_enums.hpp"
}

utils::bitwise_enum s1 = Style1;


2. 如果你不擔心enums的type-safe問題的話,那你也就不用這麼麻煩了。 :)

References:
1. bitwise_enums
2. bitwise_enums ComplierErrors

2008年12月5日 星期五

ISO 文件

最近公司在用ISO文件,今年是大檢,而且特別是工程部這邊,因為我很不小心的接下了這個工作,所以現在是一個頭兩個大,前幾年我都沒有接觸ISO啊,只有在去年是輔助的角色幫忙整理資料而已,結果今年我就硬扛下來了,我命苦了。 >_<~

另外,小公司的ISO感覺上常常都是做好玩的,都是做給所謂的ISO"老師"看得而已,然後再找一個比較會啦賽的去跟"老師"啦,再找個漂亮的行政專員陪陪老師開開會就ok了(咦~ 好黑暗? XD),這種做表面功夫的ISO我感覺比真實做ISO還累人 (應該說12月份特別累)。

明天又是忙錄的週末。

2008年12月2日 星期二

std::exception 沒有支援wchar_t的介面

很可惜的,如果你的程式是Unicode的話,exception::what並不會因此而改成傳回const wchar_t *

void log(const wchar_t* text);

void main()
{
try
{
throw std::runtime_error();
}
catch (std::exception& ex)
{
const char * message = ex.what(); // 只有const char *的版本
log(message);
}
}


一種做法是不要透過what去取得error message
(適用在寫自己的exception,底層的exception還是沒辦法)

class your_exception : public std::exception
{
public:
your_exception(std::wstring what) : m_what(what) {}
virtual ~your_exception() {}

virtual const wchar_t * message() const
{
return m_what.c_str();
}

private:
std::wstring m_what;
};

void log(const wchar_t* text);

void main()
{
try
{
throw your_exception("something error..");
}
catch (your_exception& ex)
{
const wchar_t * message = ex.message();
log(message);
}
}


但是這樣寫會有幾個問題
1. C++提供的std::exception沒辦法改寫出wchar_t的版本。
2. 如果底層真的會丟出std::exception,那你也要catch (std::exception& ex)才攔得下來,根本問題還是沒有解決。

另一種方法是後端再去把const char * 轉成wchar_t

std::wstring ToWString(const char* text)
{
std::wstring str;
size_t size = strlen(text) + 1;
str.resize(size );
MultiByteToWideChar(CP_ACP, 0, text, -1, &str[0], size);
return str;
}

void log(const wchar_t* text);

void main()
{
try
{
throw std::runtime_error();
}
catch (std::exception& ex)
{
const char * message = ex.what();
log(ToWString(message));
}


後記
1. 其實這個對有經驗的programmer根本不是問題,而且解法可能沒有太多種。
2. 所以這篇只是要做一個memo而已。 :)

2008年12月1日 星期一

小小大星球的快打旋風造型!!

哈哈,最近小小大星球的一個國外網站貼出快打旋風的造型圖片喔~
每一隻都好可愛喔 >////<... 呵呵... 如果到時候要錢才可以下載的話,那我會買下去的吧... XD













boost 的serialization export問題

今天在寫一個專案,用到了很多繼承的物件要透過boost::serialization來儲存,但是我的程式碼明明就有加入BOOST_CLASS_EXPORT選項,可是就是不明白為什麼有的class可以正常被serialization,有的則會丟出excetipn(unregistered class),後來找到這一篇文章,他裡頭有提到

为使用这些宏,必须包含boost/serialization/export.hpp,在包含该头文件之前,必须首先包含所有要使用的archive类的头文件。

嗯嗯,的確我就是在某一個.h裡include "export.hpp",而又在另一個.cpp檔include "binary_iarchive.hpp",一直都不知道boost原來在使用上還有這些細節,造成我今天半天的時候都在處理這個超乎我想像的問題。 orz....


或許改天真的要來了解一下boost::serialization的底層設計吧,加深自己對boost的認識。

2008年11月26日 星期三

擴充boost serialization 支援 CString, CTime

boost的serialization是一個很強大的工具
原本的程式架構只支援std::string等STL元件
如果你的程式有需要用到MFC的話
MFC的CString, CTime或其他class可以很簡單的擴充到boost serialization


namespace boost
{
namespace serialization
{
template
inline void save(Archive & ar, const CString& str, const unsigned int file_version)
{
std::wstring wstr(str);
ar & BOOST_SERIALIZATION_NVP(wstr);
}

template
inline void load(Archive &ar, CString& str, const unsigned int file_version)
{
std::wstring wstr;
ar & BOOST_SERIALIZATION_NVP(wstr);
str = wstr.data();
}

template
inline void serialize(Archive &ar, CString &str, const unsigned int file_version)
{
boost::serialization::split_free(ar, str, file_version);
}

template
inline void save(Archive & ar, const CTime& time, const unsigned int file_version)
{
__time64_t t = time.GetTime();
ar & t;
}

template
inline void load(Archive &ar, CTime& time, const unsigned int file_version)
{
__time64_t t;
ar & t;
time = t;
}

template
inline void serialize(Archive &ar, CTime &time, const unsigned int file_version)
{
boost::serialization::split_free(ar, time, file_version);
}
}
}


ps. 要注意一點,擴充的class要放在boost::serialization namespace裡,要不然可能會找不到對映的function

Reference
http://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/index.html

2008年11月25日 星期二

Inno Setup 包裝 Visual C++ runtime library

前言
用Inno Setup建立Visual C++的安裝程式時,如果你使用MFC Shared DLL的話,通常你都要把vcredist.exe包裝進來,不過vcredist.exe一直存在一個blocking problem,安裝的時候常常會卡在某一個畫面,有時候慢的話要三分鐘才會結束(這個問題在Visual C++ 2008 sp1有獲得改善了),而且vcredist對user來說只需要安裝一次就足夠了,因此在安裝程式的時候,可以透過簡單的語法來判斷是否需要安裝vcredist.exe。


[Setup]
Your program setup

[Files]
; Visual C++ redist
Source: vcredist_x86.exe"; DestDir: "{tmp}"; Check: NeedInstallVC9SP1

[Run]
Filename: "{tmp}\vcredist_x86.exe"; Parameters: /q; WorkingDir: {tmp}; Flags: skipifdoesntexist; StatusMsg: "Installing Microsoft Visual C++ Runtime ..."; Check: NeedInstallVC9SP1

[Code]
var vc9SP1Missing: Boolean;

function NeedInstallVC9SP1(): Boolean;
begin
Result := vc9SP1Missing;
end;

function InitializeSetup(): Boolean;
var version: Cardinal;
begin
if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9A25302D-30C0-39D9-BD6F-21E6EC160475}', 'Version', version) = false then begin
vc9SP1Missing := true;
end;
result := true;
end;


上面這樣的程式碼會先檢查User端有沒有安裝過vcredist.exe,如果沒有安裝過則解壓縮vcredist並且install,如果已經有安裝了就不解壓縮且不install。

enjoy Inno Setup

2008年11月22日 星期六

'dynamic_cast' : 'A' is not a polymorphic type


class A
{
public:
A() : m_a(1) {}

int m_a;
}

class B : public A
{
public:
B() : A(), m_b(2) {}

int m_b;
}

int main()
{
A* a = new B;
B* b = dynamic_cast(a); // error
delete a;
}


上面的程式碼在編譯時,我們最好的朋友 - complier - 會告訴你dynamic_cast那一行有錯誤,錯誤訊息應該會像下面這樣:
'dynamic_cast' : 'A' is not a polymorphic type
咦,明明B和A是有繼承體系的,為什麼沒辦法用dynamic_cast呢??
主要是dynamic_cast在做型別轉換時會依賴vftable做型別檢查
(dynamic_cast會檢查型別是否符合,不符合會傳回NULL)
而要建立vftable只要在class底下有包含至少一個virtual function就可以了
在effective C++也有提到,如果你的類別需要被繼承的話,最好將你的解構子(destructor)設為virtual
既可以加入vftable,也可以避免delete base的memory leak

所以程式碼修改成下面就ok了

class A
{
public:
A() : m_a(1) {}
virtual ~A() {}

int m_a;
}

class B : public A
{
public:
B() : A(), m_b(2) {}
virtual ~B() {}

int m_b;
}

int main()
{
A* a = new B;
B* b = dynamic_cast(a); // pass
delete a;
}


delete a, b, c;

雖然用C++在工作上也有三四年的時間了,可是有時候有一些細節的觀念還不是很清楚
可能是我不用功好好k書吧 orz.. 而且自己接觸的是Embedded System.. C++技術都沒進步的 orz..

----------------------------------------


int *a, *b, *c;
a = new int;
b = new int;
c = new int;
// ....
delete a, b, c;


上面這樣的寫法會造成memory leak,主要是因為delete a, b, c只會刪除a而已,且乎略b, c
我一開始看到memory leak的時候還蠻訝異的,明明int *a, *b, *c就是正常的,會宣告出a,b,c三個int pointer
為什麼會delete a, b, c卻只會對a動作呢??

主要是delete a, b, c裡面還包成逗號運算元
delete a, b, c 等於(delete a), b, c;
先delete a之後再對b, c取值。
所以要寫delete動作時還是乖乖的一行一行寫吧
delete a;
delete b;
delete c;

2008年11月13日 星期四

MFC如何分析Command指令

在執行程式的時候後面可以加入Command Line
ex:
dir /w *.txt
myapp.exe /service


在console C/C++時,直接分析arg等參數就可以了
而在MFC程式裡,因為MFC有將這個分析的動作包成class
所以繼承該class並重載function

底下是example
class CYourCommandLineInfo : public CCommandLineInfo
{
public:
CCommandLineInfo() : m_service(false) {}

bool IsService() const {return m_service;}

virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
{
if (bFlag)
{
if(_tcscmp(pszParam, _T("service")) == 0)
m_service = true;
}
}

private:
bool m_service;
};


BOOL CYourWinApp::InitInstance()
{
CYourCommandLineInfo cmdLineInfo;
ParseCommandLine(cmdLineInfo);
if (cmdLineInfo.IsService())
{
// ...
}

// ...
}

2008年11月12日 星期三

CMFCVisualManager的memory leak問題

國外遇到的問題,很巧的我也遇到了
http://209.85.175.104/search?q=cache:pxlLUie-0XAJ:social.technet.microsoft.com/Forums/en-US/vcgeneral/thread/8870974f-1414-4dd7-b7c3-a1c320c0e91e+CMFCVisualManager+memory+leak&hl=zh-TW&ct=clnk&cd=1&gl=tw

在使用CMFCVisualManager時,有時候結束時會有memory leak
解決方法如下:
1. 將CWinApp改成CWinAppEx就ok了,但是如果你有重載ExitInstance的話,記得要再呼叫CWinAppEx::ExitInstance() (這是我遇到的問題,忘記呼叫底層了)
2. 在關閉程式時,手動clean

CMFCVisualManager::DestroyInstance(TRUE /* bAutoDestroyOnly */);
CMFCVisualManagerOffice2007::CleanStyle();


第1種方式才是正解,只要記得call CWinAppEx::ExitInstance()就ok了
enjoy the powerful UI.

2008年11月3日 星期一

小小大星球 簡易開箱文

今天終於入手小小大星球了,但是很可惜的我沒有拿到巫毒娃娃,因為之前巴哈開始預購的時候,我還在猶鬱要買新的還是二手的,結果後來在9/30才下訂單,不過我的巫毒娃娃已經離我而去了,哭哭。

因為目前人還在公司,所以從7-11拿到小小大星球也只是開箱拍個照而已,呵呵。




相面照



開盒


一本中文手冊、一個光碟及一個英文的紙張




下班回去趕快來玩吧... XD

2008年10月29日 星期三

for Warrick

昨天看完CSI的LV 901之後...
唉~ 感覺好沈重喔~ 有幾幕感覺特別的難過...

1. Catherine聽到消息走進來的時候,那個背景音樂和Nick難過搖頭..

2. Warrick錄下來的video,當他講Grissom像他爸爸一樣在背後鼓勵他、教導他,真的是很感人的。

3. Grissom最後在教堂的講話,是會另人噴淚的那一種.. >_<~~


可以請CSI的編劇~ 下次如果真的還有人不要演的話~ 可以不要讓他在劇中死掉嗎 @_@

2008年10月28日 星期二

POD(Plain Old Data)

看書的時候,一直看到"POD"這個關鍵字,可能是我從來沒有好好把一本C++的書看完吧(還是眼睛自動忽略 orz),後來上網查了一下,在這邊分享一下好了..

POD 是Plain Old Data的簡寫,是指一些系統的int, char, float、指標、array之類的資料型別,這應該蠻好想像的,就是C++ compiler提供的內建型別,比較特別的是類別與結構,如果類別和結構帶有trivial constructor,也是POD的一種


class vector3D
{
float x, y, z;
};
struct size
{
int width, height;
};

Non-POD當然就是POD的相反囉,可能是很複雜的類別或結構。

生命週期:
1. POD: 和出現在記憶體的時間一樣
2. Non-POD: 開始在constructor,結束在destructor

所以POD和Non-POD是有差別的,因此一些memcpy, memcmp等C function不適合用在Non-POD的物件上(沒有constrctor/destructor),如果你真的使用的話,可能會造成嚴重的錯誤。

Reference:
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=32

Comment:
trivial constructor: 自動被編譯器加入的預設建構子。

2008年10月27日 星期一

Osaka Bang!

超搞笑的大阪人.. XD

程式設計師的格言

在網路上看到一篇很有趣的文章(程式設計師的格言),我想每一位程式設計師看完一定會笑出的來 :)
裡頭有幾項比較精典的,我把他列出來

  1. 要殺一個程式設計師不需要刀,改三次規格就好
  2. 程式的異常該稱為「bug」還是「規格上的限制」是看期限還剩多久決定的。
  3. 多想個10秒鐘,你可以不說「嗯,這個做得到」。
  4. 上線後的除錯才叫做bug。
  5. 啊,那是微軟的規格。
  6. 過了三天就是別人寫的程式碼。
  7. 就算程式裡沒bug,編譯器會有bug。
    就算編譯器沒bug,OS會有bug。
    就算一切都沒bug,客戶會決定什麼是bug。
  8. 『coding』=複製貼上的工作



以下文章引用自:
http://buttaiwan.wordpress.com/2008/10/12/programmers_rule/


程式設計師的格言(盜作不少)
譯自http://www2.biglobe.ne.jp/~oni_page/other/etc/pr03.htmlhttp://mixi.jp/view_community.pl?id=1772737
(版本2 2008/10/12更新)
譯註SE是日本軟體公司裡程式設計師的頭子。自己不太寫程式,主要工作是跟客戶確認規格。程式設計師多半自己不面對客戶。跟PM又不一樣。(有什麼比較貼切的職稱翻譯嗎?)
—————
1每天有24小時。所謂的「今天之內」,是指到明天早上為止。
2程式不會照自己所想的跑。只會照所寫的跑。
3需求規格在程式寫完後才會敲定。基本規格要客戶看到成品後才會決定。詳細規格要使用者用過後才會確定。
4我對軟體設計的方式導出的結論,有兩種方式。一是把軟體設計得單純到很明顯不會有缺陷,不然就是把軟體設計得複雜到沒有明顯的缺陷。- C.A.R.Hoare
5程式碼不要在開發現場寫! 去客戶那寫!除錯不要在期限前做! 上線後再做!
6畫面藍了。
7先說「沒辦法」的人贏。
8有意見的話你寫
9要殺一個程式設計師不需要刀,改三次規格就好
10首先要先懷疑別人,被懷疑的人或許會把問題解決掉。(註:通常會「先懷疑自己」)
11開發沒有終點。只有釋出(release)。
12無論規格多晚才能確定,結案期限永遠不會變。這是所謂的「期限守恆定理」。
13客戶總是覺得水跟追加需求是不用錢的。
14付錢愈計較的客人愈囉唆。
15在排定開發行程時,總是視而不見一些連小學生都會的算數。業務部門總是一堆不知道1+1=2的人。
16一個人掛了大家都掛了。
17bug過了一晚可能就變成規格了。
18好的規格找一個天才不如找三個凡人。爛的規格找一百個凡人不如找一個天才。
19客製軟體中30%的價格用在確認規格上。30%用在修改規格上。30%用在找bug。結果初期規格反映在價格上占的比例只有10%。
20對客戶來說SE是部下,程式設計師是家畜。對SE來說客人是錢,對程式設計師來說顧客是看不見的病毒。除了弄完程式以外,沒有其他驅除的辦法。
21顧客想受SE喜歡,要自己了解到系統開發需要時間與金錢,早點確定規格。SE想受顧客喜歡,則要讓程式設計師討厭自己。
22很多SE跟程式設計師都暗自想著有錢有閒的話什麼系統都想自己動手做,不過都沒這種機會。
23品質的劣化程度依規格改變的次數與規模而定。
24業務是認為空想能夠實現的夢想家。SE則是深信任何障礙都能突破的冒險家。程式設計師則是被夢想家和冒險家拋到漆黑海裡的漂流者。
25有才能的程式設計師第一次看到設計細節時,要先理解程式的目的。接下來要設法讓SE了解到以指定的方法、工時並無法完成這個工作。
26程式是運氣與直覺堆砌而成的奇蹟。若不具備這兩者,不可能以這樣的工時實現這樣的規格。修改規格是對奇蹟吐槽的褻瀆行為。而追加修改則是相信奇蹟還會重現的無謀行動。
27程式設計師聽了「把自己當作顧客去著想!」而開始思考。啊,像夢一樣。
28對於因為興趣而寫程式的人來說,所謂的技術是程式語言能力。對於因為工作而寫程式的人來說,所謂的技術是邏輯思考能力與人際溝通能力。程式語言可以看著手冊溝通,客戶不行。
29程式系統在交貨之前會不斷縮小。先用元件定義取悅老闆。再拿經費概算要部長妥協現實的方案。在運用會議中,課長會嘗識減少自己責任範圍。在細節會議中,負責人會把範圍縮到自己記得的部分。
30SE需要持久力,程式設計師需要爆發力。
31準時離開公司,工作會變多。
32完美的程式需要完美的時間與金錢。聽說揮霍著美國的國家預算的NASA,也覺得時間跟錢不夠。
33詳細設計要在程式碼的註解裡做完。註解是唯一的自衛手段,至少要讓自己看懂。
34還有時間看程式碼的話就執行他。CPU跑得比腦細胞快。至少這時候可以休息。
35程式的異常該稱為「bug」還是「規格上的限制」是看期限還剩多久決定的。
36所謂便服日,好像社會上把他叫做假日(註) 日本有些公司會有所謂便服日(不用穿西裝的日子),通常是星期五,但…
37地獄持續一段時間後,充滿殺氣的怒吼會變多。再持續一段時間,說話會變少但牢騷會變多,壟罩在凝重的氣氛裡。再持續下去,反而會海闊天空,四周洋溢充滿活力的聲音。這種狀態稱為「Programmer’s High」,也是倒下來的人開始出現的時候。
38遠處的火災一定燒到這裡。
39禱告,然後跑吧。
40程式不是用腦記的,要用身體記住。
41明天能放假的話死了也罷。
42外面有下雨耶,昨天開始下的嗎?
43若不能心靜不移,身體會掛。若不讓自己殘忍,自己會被殺。
44客戶會說謊,業務會作夢,SE會做白日夢。程式設計師則惦惦。(愈來愈自言自語)
45(日文文字遊戲)SE總是不負責的說「別逞強」,業務總是無理取鬧不准說「沒辦法」。
46規格書就像航海圖,客戶則是洋流。洋流陰晴不定,航海圖就變垃圾。程式設計師必須在沒有航海圖的海上憑自己的力量找到大陸。
47再嘮嘮叨叨下去也是要付錢的。
48多想個10秒鐘,你可以不說「嗯,這個做得到」。
49人是無法從別人失敗記取教訓的動物。砍成本、改規格、加需求、趕上線,從來沒有人從眾多失敗中記取教訓。
50老手用來提振精神的魔法格言:「不過比起以前來說算是…」新人用來提起幹勁的魔法格言:「把這件工作做完的話…」他們還不知道工作是沒有終點的。
51所謂交案期限,是指開發現場從公司換到客戶那裡的日子。
52程式、SE、經理不是職務。是逃不掉的責任。
53業務是最難搞的客戶。
54能夠迅速想到解法的程式設計師太多了。他們能用一分鐘想到方法,用一天去寫程式。不需要花一小時想到解法,再用一小時去寫程式。- Jon Bentley
55漂亮的規格,可以從沒有bug出現看出來。明明爛的就是設計,為什麼是這樣…
56上線後的除錯才叫做bug。
57追加需求確定後交貨期限就無法確定,交貨期限確定後追加需求就無法確定。這稱為「追加需求與交貨期限的測不準原理」。
58除三個錯就會冒出一個錯。這稱為bug的無窮迴圈。
59不祥的預感總會實現。不過程式設計師不會去煩惱不祥的預感,那是SE的工作。
60要解決地獄的辦法,就是客戶把錢交出來。
61不懂電腦的操作者是發現bug的天才。而且無法重現。
62每次開會就更改規格的客戶,他的操作手冊要等到操作寫好的程式後才能寫出來。
63搞不懂的時候,Currency(長整數)比Interger(整數)好用。Variant(字串、數字都能存的萬能變數)又比Currency(長整數)好用。安全第一。(VB程式設計師如是說)
64啊,那是微軟的規格。
65程式設計師所不滿的規格也一定會讓客戶不滿。(這是說程式設計師覺得難寫的地方常常是SE溝通有落差)
66程式設計師需要的技能,包括交涉、時程管理、業務分析、提案、設計、程式語言、架構、維護、使用。SE需要的技能則減掉程式語言、架構、維護與使用。專案經理需要的能力則再減掉業務分析、提案與設計。業務需要的能力再扣掉時程管理。
67正因為健康,才能做不健康的事。
68規、規格、是規格啦。不過有一點跟規格不太一樣啦。
69那是你說的規格。
70開發室沒有窗戶,那是因為以前…
71爛了也是因為規格。
72SE: 真沒辦法。PG: 也沒註解。(碰到不知道是誰寫的程式,大家都束手無策的狀態)
73為什麼你不能兩三下解決掉他啦。因為之前兩三下搞定的東西也被你兩三下就否定了。
74不會動的bug就只是普通的bug。(會動的bug則能視為規格)
75今天好好清理bug,bug應該死光了吧。咦?Windows也死了唷。
76客戶不會去想最壞的情況。要他面對最壞的情況,他會認為是漫天開價。SE則會顧慮最壞的情況,準備應付最壞的情況。程式設計師比誰都早預料到最壞的情況,而無視最壞的情況。
77唯一不產生bug的方法,就是不寫程式。第二好的方法,就是在時程跟人員確定之後的每次改規格,都重新檢視過整個專案。
78共同責任是程式設計師的責任。管理職?那是啥?好吃嗎?我沒吃過耶。
79如果可以改行的話,想找個準時下班不叫「逃跑」的工作。
80對職業程式設計師來說,漂亮的程式是單純而自然的邏輯、簡單而基本的指令、豐富的註解,也就是新手程式設計師也能馬上動手改的程式。而要寫租這樣的程式,需要單純、簡單、美麗的規格。但可惜客人總是喜歡搞很複雜。
81設計者應該是不該要求製作者製作出超過設計以上內容的吧…
82無論是做的比規格書裡的多,還是只照規格書裡的寫,SE都會找程式設計師的碴。所以程式設計師只做規格書裡的寫的內容。
83SE對程式設計師說的「常識」每三小時變一次。
84自己看規格書。不能跑的是規格。
85「沒辦法」是要看把一天當多少小時來算。一天常常指的是3人日,一個月常常是指4.5人月喔。
86工時要減掉一半的單體測試與一半的系統測試,而交貨期則要另外加上上線後的兩個月。
87能拿到錢的規格變更稱為「受理項目」,拿不到錢的規格變更則稱為「SE的規格確認失誤」。程式設計師是這麼看的。
88累了。我想睡了。可以回家嗎。(累了吧,我也累了。好累喔怎麼了。反正就是規格啦,管他的)
89試圖降低成本的話,為了配合預算,品質會下降,不過漫天開價做出來的品質也不見得好到哪裡去。
90REDO到底該怎麼唸一直搞不懂。是利斗嗎、李度嗎、R E D O嗎,難道是 red 零 嗎? 拜託加上注音吧。(譯註:我比較煩惱 Linux)
91有人在程式碼註解裡寫日記。像「今天是雨天…」,「想回家…」之類的。甚至還有「修改日: 2003/10/10 不能同意你更多」這種註解出現。說到這個,好像也看過「吃大便」這樣的註解。
92小學生時第一次看到電腦國中時第一次學會怎麼用高中與大學學會程式語言出社會後才發現自己走錯路
93「不要讓老闆當業務比較好」
94說來說去,要去研究根本不知道為什麼會動的東西為什麼不會動了,找拿破崙來也沒搞頭。
————————
ex 1就算程式裡沒bug,編譯器會有bug。就算編譯器沒bug,OS會有bug。就算一切都沒bug,客戶會決定什麼是bug。
ex 2規格與規格書是不同的東西。
ex 3比期限更重要的是靈感與睡眠。
ex 4比知識與經驗重要的是手冊與時間。
ex 5能動就好了,能動的話…
ex 6過了三天就是別人寫的程式碼。
ex 7 (大搜查線系列)規格變動不是在會議室裡發生的!是在現場發生的!
ex 8 (大搜查線系列)異常不是在模擬測試時發生的!是上線後才會發生的!
ex 9漂亮的設計三天或許就膩了骯髒的設計三天就習慣了
ex 10bug與規格是一體兩面
ex 11電腦裡沒有bug,bug常在人心。
ex 12無論怎麼檢查,不管怎麼確認,上線前一晚就是睡不著。(RFC968)
ex 13估價需要1%的經驗與99%的直覺
ex 14沒有什麼事情比直接讓找不到任何bug的程式直接上線還要可怕的了。
ex 15・『程式設計師』=能將SE條理不通的說明翻譯成程式碼的高手・『SE』=與客戶討論改寫規格書、與程式設計師討論後再改寫規格書,程式出貨後還要繼續改寫規格書的人・『PM』=每天修改自己定下的行程表的人・『業界老鳥』=臉色蒼白缺乏表情的人・『外包』=幫不會寫程式的正職員工寫程式的人・『coding』=複製貼上的工作・『單體測試』=指開始寫程式・『除錯』=把程式碼註解掉的工作・『新同事』=在火燒屁股的專案火上加油的人・『出貨日』=把只完成一半的系統上線的日子・『末班電車』=業界平均的下班時間・『颱風假』=一年一度可以準時下班的業界假日
ex 16當誰寫的程式碼跑出bug時,那個人大概都不在了(墨菲定理?)
ex 17最終手段「重開機」意外的常常都很有效
ex 18最強藉口以前「那是硬體的極限」現在「那是Windows的規格」
ex 19「程式碼的可信度,不會比寫的人還可信。」

2008年10月16日 星期四

Inno Setup 如何在安裝程式前,先檢查並關閉之前的程式

在建立Installer時,有可能user的程式因為還在執行,而Installer無法寫入。
底下是在Install時直接關閉前一個程式。

[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var appWnd: HWND;
begin
if (CurStep = ssInstall) then
begin
appWnd := FindWindowByClassName('your class name');
if (appWnd <> 0) then
begin
PostMessage(appWnd, 18, 0, 0); // quit
end;
end;
end;

2008年10月14日 星期二

Visual C++避開max, min macro的問題

WinDef.h內有定義max, min等macro (當你#include windows.h, WinDef.h就會被引入了)

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif


這會造成命名的衝突以及使用上的問題,例如我假設要使用stl的numeric_limits來取得double的最大值

#include
#include

using namespace std;

void main()
{
double maxValue = numeric_limits::max(); // 錯誤,因為max是一個macro,會先被preprocessor處理
cout << maxValue;
}


解決方法:
只要在#include WinDef.h之前,#define NOMINMAX或是在專案設定的Preprocessor裡輸入NOMINMAX就可以關閉max, min macro了



-----------------------------
有太多的C++書籍呼籲你不要再使用#define來定義function了,而是改用inline等方式

inline keyword

Sometime in the late 1980s inline was a big shot. Today the best thing to do about this keyword is ignore it completely. Chances are high that your compiler and linker are smart enough to figure out by themselves which functions are better candidates for inlining and which ones aren't. Explicit inline declarations thus merely get in the compiler and linker's way. [ref]

整段話的意思呢,就是不需要去刻意的加入inline keyword,完全由complier幫你做最佳化,因為你加入inline keyword,還是由complier來決定要不要使用inline。

如果有考慮要讓complier來做implicit inline的話,必需要把你的function定義寫在.h檔 (class body)裡,如果寫在cpp的話,implicit inline不會有作用。




References
--------------------------------------
1. 30 C++ Tips in 30 Days: Tip # 3 inline Do's and Don'ts

explicit constructor

考慮一個問題

class MyClass
{
public:
MyClass();
MyClass(BOOL bAutoDelete = TRUE);
}

int a = 4;
MyClass b;
b = a; // 這一行complier竟然會沒有error和warning??


因為complier在編譯的時候會implicit做一些轉換,例如在這一個MyClass assignment的地方
1. 找MyClass有沒有支援operator=(int)的function (找不到!!)
2. 找int 有沒有轉換成MyClass的conversion function (找不到!!)
3. 找MyClass有沒有int 的constructor (bingo!! ps1)

在這個情況底下.. 我們需要的是 b = a.. complier應該要給我們一個錯誤訊息才對..
implicit的constructor不是我們需要的.. 所以要在constructor前面加一個explicit
避免complier幫你做隱式的轉換


class MyClass
{
public:
MyClass();
explicit MyClass(BOOL bAutoDelete = TRUE);
}

int a = 4;
MyClass b;
b = a; // error
b = MyClass(a); // ok




ps1 因為BOOL是實際上是int (Visual C++)
typedef int BOOL;
#define TRUE 1
#define FALSE 0

2008年10月13日 星期一

shared_ptr

shared_ptr是boost裡頭很重要的東西,可以讓C++ programer完全省掉delete memory的動作
目前shared_ptr已經加入而TR1裡頭了..
Visual C++ Feature Pack有完整的支援TR1..
http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/sp_techniques.html#preventing_delete

舊的寫法

class B
{
private:
int m_a;
double m_b;
};

int main(int argc, char *argv[])
{
B* b = new B;

// do something

delete b; // 要記得delete b

return 0;
}


使用shared_ptr

#include

class B
{
private:
int m_a;
double m_b;
};

int main(int argc, char *argv[])
{
std::shared_ptr b(new B);

// do something

// 不需要delete b

return 0;
}

2008年10月7日 星期二

VS2005的MFC Project 轉成VS2008的Warning問題

直接將VS2005的專案轉成VS2008的話~ 編譯時會出現一個Warning
option 'Wp64' has been deprecated and will be removed in a future release
應該是VS2008不支援64-bit環境的檢查動作了~ 至於真正的原因... 還不知道

// Solution
Project -> Properties -> C/C++ -> General -> Detect 64-bits portability Issues -> NO

讓程式同時只能有一個Process被執行

在Windows下,同一支程式可以被執行多次..
要如何限制程式同時只能被執行一次呢呢?


BOOL CMyApp::InitInstance()
{
HANDLE hMutex;
if ((hMutex = CreateMutex(NULL, TRUE, MUTEX_NAME)) == NULL)
return FALSE; // 建立Mutex失敗

// 已經有別的Process被產生了
if (GetLastError() == ERROR_ALREADY_EXISTS)
return FALSE;
}

神鬼傳奇3

昨天和寶貝一起去看神鬼傳奇3..
因為我以前只有在第4台看過第1集而已~ 我一直以為印和闐是主角的說.. 呵呵~
因為寶貝一二集都有看過了~ 而且昨天是我們中國的情人節~ 所以就和寶貝一起去看了...

整個劇情都還蠻緊湊的.. 常常場景一直換~ 像是沒時間可以交待整個劇情一樣 (整部片大概2個小時吧)
一開始先交代一下中國的秦朝的劇情並且埋了一些伏筆~ 之後主角的兒子在中國挖出了秦始皇的棺木 (奇怪~ 怎麼對其他金銀財寶沒興趣)
之後不小心讓秦始皇復活了~ 之後便是主角一家人和秦始皇的對決戲碼囉~
整個劇情是中英文交差... 主要還是英文... 可是因為很多中國人~ 所以中文也蠻多的~ 有時候主角兒子也會來幾句聽起來很怪的中文... 害我看到一半想笑出來
不過有一幕我感覺比較奇怪... 當紫菱在唸咒文要喚醒死去的士兵時~ 竟然是講英文 = =... 如果是紫菱在2000年來因為無聊學了一些中文到是還好~ 怎麼死人聽得懂英文呢??
而且咒文應該是用西藏 古文寫的吧~ 怎麼聽起來像英文呢... orz

裡面最帥的一幕應該是Jet Lee變身吧~ 嗯~ 帥氣十足...
另外當我們在電影院拿票的時候~ 那個工作人員說~ 你訂的票是「神鬼奇航3」是嗎?? 我差點笑出來... XD


最後附一張神鬼傳奇3的劇照吧






























======
這個是August 8, 2008 的文章了

my boss

有時候我真的不知道他在想什麼...
在我最忙的時候從我的手邊抽人走...
有時候專案直接不透過我直接call人做...
可是有時候自己在測試東西的時候,又不直接去問測試人員結果,偏偏要找我問東問西..
這樣的中繼站會當得很爽嗎?? =..=

更何況讓一個不是該專案的負責人去出差?? 去回答客戶問題?? (只是後來修改小程式,原本的負責人都還在)
一整個好怪... 唉..

要嘛就全部我們來負責~ 要嘛你就自己負責弄.. 不要來煩我們...

2008年10月3日 星期五

vector::erase和iterator的問題

vector::erase後,原本的iterator會失效
所以在使用for-loop + erase要特別注意

help有指出,vector::erase會回傳一個有效的iterator


A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence.
http://www.cplusplus.com/reference/stl/vector/erase.html




std::vector values;
for (std::vector::iterator it = values.begin(); it != values.end(); )
{
if (*it > 10)
{
it = values.erase(it);
}
else
{
++it;
}
}

LinkWithin

Related Posts with Thumbnails