2009年11月30日 星期一

C++ string

http://anaturb.net/C/string_exapm.htm

#include <string>
using namespace std;

每次都忘記 namespace這回事

2009年11月29日 星期日

C++ 中 struct 與 class keywords 的差異

http://screamlab-ncku-2008.blogspot.com/2009/10/c-struct-class-keywords.html

C++ 中允許使用者在宣告(declare)、定義(define)型別時,使用 struct, class 兩個不同的關鍵字(keyword)。由於兩種都可以,因此很容易讓人好奇兩者是否存在必要性的差異。

在宣告時,使用 struct 或 class 都可以告訴 compiler 這是一個新的自訂型別,但在定義(define)時則有差異,根據最新 C++ standard
的描述, class 和 struct 對於 class definition 的差別在於:
1. 對於 member 的 default access level 不同(std.11);
2. 對於 base class 的default access level 不同(std.11.2)。

其不同在於 struct 是寬鬆的,都以 public 為預設。

上面的敘述很簡單,會引發一些聯想、甚至遐想:

Q1: 所以也可以使用 struct 寫多重繼承?多形?實現建構/解構子概念? 或者實作interface?就算可以,那為何會有class的產生?它不正是為了延伸structure的概念,達到更方便的OOP設計嗎?class 跟 struct 是可以互相繼承的嗎?
A1: 是的,可以。

Q2: 如果 Q1 的程式存成 .c ,可以compile過嗎?
A2: 沒辦法,C 語言不支援

Q3: 剛提到的差異是 class definition 上的,至於其他地方有差異嗎?
A3: 有的,像是 template 的 parameter list 只允許 class, typename ,無法使用 struct,因為 template 的設計,一開始就沒有打算和 C 相容。

Q4: 扣除些微差異,class 和 struct 幾乎是一樣的東西,為什麼 C++ 會同時引入兩個 keywords 呢?
A3: C++ 原本叫做: C with Class 。它的重要理念之一是與 C 相容,不過確實也是有不相容的地方,C++ Standard 的附錄 C 就列舉了 C++ 與 C 不相容的部份。因此為了這相容性,不可能將 struct keyword 拿掉,引入 class 這個新的 keyword ,它所帶來的不只是 parser 要多 parse 一個字,更重要的是其背後的抽象性、封裝性以及滿足人們對於 OO 的期待心理。而且以 Google 上"C++ struct class?"的搜尋,會先冒出一堆兩者的差異、比較的網頁就知道,class 的確辦到了"混淆視聽"的效果 : )

Q5: 都聽你在講,有沒有權威一點的說法啊?
A5: Stanley Lippman 的著作: Inside The C++ Object Model,裡頭有一個章節叫做:Keywords, Schmeewords;開頭就是這樣說的:

One answer to the question of when, if ever, you should use a struct declaration rather than a class declaration then, is whenever it makes one feel better.

是的,重點在於 struct, class 定義出的 attributes, member functions 是否能符合你的需求期望。兩者的差異在於主觀的感覺: struct 用在 data aggregation,class 用在 Object oriented 或 object based 上。

Q6: 那為什麼不在 C++ 內限制 struct 只能宣告一般 aggregation type,不能有 access level 、member function 等能力呢?
A6: 其實原因很簡單:只是為了 C 到 C++ 遷移順利。 C++ 草創支出,除了效能是個大家關注的議題之外,什麼時候使用 struct 取代 class 也是常被問起的問題,與其涇渭分明的兩套標準,不如以一貫之,Bjarnet Stroustup 在 The Design and Evolution of C++ 這樣講著:

Maybe we could have lived with two set of rules, but a single concept provides a smoother integration of features and simpler implementation.尤其重要的是,嚴格區分兩者可能使得社群分裂(原文: community would fall into two distinct camps that would soon stop communicating.)

ㄜ,除了上面講的顏色對不對外,你覺得下面的 code 該編譯過還是不過呢?
// Forward Declaration
struct MyClass;
// Definition
class MyClass {
...
};
這應該是一致性問題,還是我們得一定要 compiler 嚴守 langauage 規範,幫我們挑出來呢? (以上很哲學又考古! )

Q7: 那我可以說 struct 原本要被幹掉嗎?
A7: 不算是要被幹掉,因為一開始就打算與 C 相容,所以不會幹掉,考量是:
1. 要不要引入新的 keywrod -- class
2. 引入 class 後,是否要讓 struct 與 class 不相容,使用兩套 rules。
而 後的決定是:引入 class ,class 和 struct 使用同一套 rules (只差別在 default accessibility),而事實也證明 class 帶來令人滿意的效果,不管是心理的、實務上的。心理的上的話,套句 Lippman 的話:你會講 base class 還是 base struct ,雖然只是小小的哲學問題,卻還是得到滿足。

Q8: 我搞混了,那到底什麼時候該用 struct 、什麼時候該用 class?
A8: 我想 C++ 期望使用者自決。但我想可以分成兩個層面來看。先說心理層面:這是個 makes one feel better 的問題。
xxx MyClass {
public:
void func();
private:
int val_;
};
xxx 是 class or struct 都好,因為實際描述 MyClass 行為的是 class body 中的程式碼,而不是 struct 或 class。
另 一個層面則比較實務:我想要 struct 或 class 定義出來的型別,其所產生的 object 與 C 是真正相容的,那就得考慮到 C++ 的 object model 和相關運算,簡單來說:要在 C++ 產生跟 C 相容的 object ,你的 C++ 型別必須是個 POD (Plain Old Data),standard 對於 POD 有其定義(std.9),或是上 Google 搜尋都可以看到,偷偷引用 wiki 的描述:
A POD type is a C++ type that has an equivalent in C, and that uses the same rules as C uses for
1. initialization
2. copying
3. layout
4. addressing
對我自己來說,什麼時候會使用 struct:
1. 想產生與 C 相容的 object 時,我會使用 struct 這個關鍵字,因為它帶有我對 C 的遐想,然後嚴格遵守 standard 對 POD 的規範。
2. 某些型別描述的對象很簡單(不太有(甚至沒有)繼承架構、抽象介面、生命週期短等),使用 setter, getter 又很麻煩時,那我會選使用 struct ,像是:
struct ParserResult {
bool Match;
int lineNo;
};
每個人都可以有自己一套結論!

Q8: 我試過了你這篇文章上弔詭(Paradox)的code:
struct MyClass;
class MyClass {};
/*
*warning C4099: 'MyClass' : type name first seen using 'struct' now seen using 'class'
*
*是的,可以通過編譯,但會出現如此警告。
*因此將class、struct調換過來如下:
*/
class MyClass {};
struct MyClass;
/*
*錯誤訊息如下:
*warning C4099: 'MyClass' : type name first seen using 'class' now seen using 'struct'
*/
A8: 揪甘心,這就是答案。記住:你的血統(class, struct)不代表什麼,重要的是你的所作所為(class body)

2009年11月26日 星期四

Detecting Windows SDK version using macros

#include "ntverp.h"

#if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 3790
#pragma message ("********************************************"
#pragma message ("Error: You need the latest Microsoft Platform SDK to compile this project.")
#pragma message ("********************************************"
#endif


There are other constants defined in the header which may be of use to you. I believe my preprocessor directives above simply check that VER_PRODUCTBUILD is at minimum Platform SDK for Microsoft Windows Server 2003. There is another constant VER_PRODUCTBUILD_QFE which I *think* can determine patches and service packs.

Best Wishes,


-David Delaune



http://www.codeproject.com/Messages/2997680/Detecting-Windows-SDK-version-using-macros.aspx



看到這個,以後...也許會有用

2009年11月25日 星期三

MFC的訊息

搞了很久,才發現原來是自己多事造成的問題。總之,先大致解釋一遍好了:

如果動態產生了一個物件,例如CBotton,把它的click event 接來parents的流程應該是這樣:

1. 當然要定義一個ID

#define IDC_BUTTON_UNICODE              1077

2. 利用這個ID去create它

m_Unicode.Create(_T("My Unicode Button"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, rect, this, IDC_BUTTON_UNICODE);

this是parents,message 應該會傳去給parents

3. 再來就是在message map 中加入它

BEGIN_MESSAGE_MAP(CRulerRichEditCtrlDemoDlg, CDialog)
    //{{AFX_MSG_MAP(CRulerRichEditCtrlDemoDlg)
    ON_BN_CLICKED(IDC_BUTTON_UNICODE, OnButtonUnicode)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

4. 最後就是定義函式

void CRulerRichEditCtrlDemoDlg::OnButtonUnicode()

 

我搞砸的部份在於,我定義了一個

class WUnicodeButton : public CButton

原來照上面的做也就OK了,但我多事在這個class內部又去收click event,結果外面就收不到了,真是畫蛇添足呀!

 

相關的做法可以參考這裡:

http://www.codeproject.com/KB/cpp/DynMsgMap.aspx

2009年9月29日 星期二

dxdiag

dxdiag可以搜集系統相關資訊,相當詳細。

2009年8月17日 星期一

ASSERT

ASSERT 只會用在debug,assert 則是標準ANSI C,debug, Release都會用。


_ASSERTE(SUCCEEDED(hr) && "Create DOMDocument40 failed");
能秀出後面的字串

2009年7月29日 星期三

PathFindExtension 居然這麼難!

今天為了這個搞到快瘋掉。

最後的成果是這樣的:

ILenum  GetILImageType(const char* filename)
{
            string name_ext = PathFindExtension(filename);
            std::transform(name_ext.begin(), name_ext.end(),name_ext.begin(), ::toupper);

            if(name_ext.compare(".JPEG") == 0)
                return IL_JPG;
            if(name_ext.compare(".JPG") == 0)
                return IL_JPG;

........

return IL_TYPE_UNKNOWN;

 

}

看起來很簡單是吧!?其實有夠痛苦!

LPTSTR PathFindExtension(      
    LPCTSTR pPath
);
要加include,沒問題,很直覺
#include <shlwapi.h>
結果,link時過不了,頭超大,幸好後來找到這個:
#pragma comment(lib, "Shlwapi.lib")
 
然後白忙了半天發現,char* 可以直接轉成LPCTSTR,LPCTSTR也可以直接轉成 string。真方便。
接下來也是痛苦,要全轉成大寫居然是件這麼困難的事!
std::transform(name_ext.begin(), name_ext.end(),name_ext.begin(), ::toupper); 
這個可以,不過也要include
#include <algorithm> 
然後要做String 的比對,看半天才知道要用compare。
 
真的是,講沒幾分鐘...寫起來真是要人命!
 

2009年4月7日 星期二

Multi hread

.h
//////
HANDLE m_hLoadingThread;
DWORD m_dLoadingThreadID;
BOOL m_bLoadingThreadFlag;
static DWORD WINAPI LoadingThreadProc(LPVOID pThis);



//////////////////////////////////////////
.cpp
///////
///Start/////

m_hLoadingThread = ::CreateThread(NULL, 0, CUPnPAction::LoadingThreadProc, this, 0, &m_dLoadingThreadID);


///RUN/////
DWORD WINAPI CUPnPAction::LoadingThreadProc(LPVOID pThis)
{
char ErrMsg[MAX_PATH];
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

OutputDebugString("LTP_Loading thread start\n");

CUPnPAction *pUPnPAction = (CUPnPAction*)pThis;


pUPnPAction->m_bLoadingThreadFlag = TRUE;

do
{

} while (pUPnPAction->m_bLoadingThreadFlag && ulMatches > ulStartIndex && SUCCEEDED(hr));

return S_OK;
}


///END/////

if (0 != m_hLoadingThread)
{
DWORD dwExitCode = 0;
GetExitCodeThread(m_hLoadingThread, &dwExitCode);
if (STILL_ACTIVE == dwExitCode)
{
m_bLoadingThreadFlag = FALSE;
WaitForSingleObject(m_hLoadingThread, INFINITE);
}
CloseHandle(m_hLoadingThread);
m_hLoadingThread = 0;
}

2009年4月6日 星期一

OutputDebugStringW

如果遇到這個型態,其它的都要改成W型態,例子:

wchar_t ErrMsg[MAX_PATH];

wsprintf(ErrMsg, L"LTPTime_ CGGOpenFromFile::_updateLocalFileItem FOR loop time usage= %d \n", dTickCountB - dTickCountA);

OutputDebugString(ErrMsg);

//////////

char DebugString[256];
sprintf(DebugString,"[DTCP]Condition meet to set ICT to %d\n",IctToApply);
OutputDebugStringA(DebugString);

2009年2月17日 星期二

WinDVD10 Slider

  • Click on Progress Bar, here will be called:
    d:\Projects\WinDVD\Main\DVD\Source\windvd10\WinDVD\BaseUI\dvdUI_PlayCtrlBar.cpp
    bool CDVD10UIPlayerCtrl::TimeSeek(long nTime)

 

  • Where is Progress Bar? It is here:
    d:\Projects\WinDVD\Main\SkinTool\LIBSKINDK\PlusSliderInfo.cpp