2010年1月31日 星期日

CuToolhelp - Takes a snapshot of the specified processes

//  Takes a snapshot of the specified processes




// CuToolhelp.h


class CuToolhelp  
{
    HANDLE  m_hSnapshot;

public:
    CuToolhelp();
    virtual ~CuToolhelp();

    BOOL CreateSnapshot(DWORD dwFlags, DWORD dwProcessID = 0);
    void CloseSnapshot();

    BOOL ProcessFirst(PPROCESSENTRY32 ppe) const;
    BOOL ProcessNext(PPROCESSENTRY32 ppe) const;
    BOOL ProcessFind(DWORD dwProcessID, PPROCESSENTRY32 ppe) ;
    BOOL ProcessFind(wstring strExeFile, PPROCESSENTRY32 ppe) ;
};


// CuToolhelp.cpp



CuToolhelp::CuToolhelp()
:m_hSnapshot(INVALID_HANDLE_VALUE)
{

}

CuToolhelp::~CuToolhelp()
{
    CloseSnapshot();
}

BOOL CuToolhelp::CreateSnapshot(DWORD dwFlags, DWORD dwProcessID)
{
    CloseSnapshot();

    if( dwFlags == 0 )
    {
        m_hSnapshot = INVALID_HANDLE_VALUE;
    }
    else
    {
        m_hSnapshot = CreateToolhelp32Snapshot(dwFlags, dwProcessID);
    }

    return (m_hSnapshot != INVALID_HANDLE_VALUE);

}

void CuToolhelp::CloseSnapshot()
{
    if( m_hSnapshot != INVALID_HANDLE_VALUE )
        CloseToolhelp32Snapshot(m_hSnapshot);
}

BOOL CuToolhelp::ProcessFirst(PPROCESSENTRY32 ppe) const
{
    BOOL fOk = ::Process32First(m_hSnapshot, ppe);

    // Remove the "[ System Process]" (PID = 0)
    if( fOk && (ppe->th32ProcessID == 0 ))
        fOk = ProcessNext(ppe);

    return (fOk);
}

BOOL CuToolhelp::ProcessNext(PPROCESSENTRY32 ppe) const
{
    BOOL fOk = ::Process32Next(m_hSnapshot, ppe);

    // Remove the "[ System Process]" (PID = 0)
    if( fOk && (ppe->th32ProcessID == 0 ))
        fOk = ProcessNext(ppe);

    return (fOk);
}

BOOL CuToolhelp::ProcessFind(DWORD dwProcessID, PPROCESSENTRY32 ppe) 
{

    BOOL bFound = FALSE;
    for( BOOL fOk = ProcessFirst(ppe); fOk; fOk = ProcessNext(ppe) )
    {
        bFound = ( ppe->th32ProcessID == dwProcessID );
        if( bFound )
            break;
    }

    return (bFound);

}
BOOL CuToolhelp::ProcessFind(wstring strExeFile, PPROCESSENTRY32 ppe) 
{

    BOOL bFound = FALSE;
    for( BOOL fOk = ProcessFirst(ppe); fOk; fOk = ProcessNext(ppe) )
    {
        bFound = (strExeFile == ppe->szExeFile);
        if( bFound )
            break;
    }
    return (bFound);

}

2010年1月30日 星期六

TuPowerNotification -

//
class PowerNotificationTest
{
private:
    TuPowerNotification<PowerNotificationTest> uPowerNotification;

public:
    PowerNotificationTest() {}
    ~PowerNotificationTest() {}

    void Init()
    {
        //初始化 TuPowerNotification
        uPowerNotification.CombineElement(this, PowerNotificationTest::PowerNotify);
        uPowerNotification.RequestPowerNotifications();
    }

    void PowerNotify(PPOWER_BROADCAST ppower_broadcast)
    {
        switch(ppower_broadcast->Message)
        {
           //取得 power status
            case PBT_TRANSITION:

                break;
            case PBT_RESUME:


                break;
            case PBT_POWERSTATUSCHANGE:

                break;

            case PBT_POWERINFOCHANGE:
                break;
        }
 }



// TuPowerNotification.h

template <typename T>
class TuPowerNotification : public CuPowerNotification
{
    typedef void ( T::*POWER_NOTIFICATION_PROC)(PPOWER_BROADCAST ppower_broadcast);
    POWER_NOTIFICATION_PROC m_fpPowerNotificationProc;
    T *m_pElement;
public:

    TuPowerNotification();
    ~TuPowerNotification();
    void CombineElement(T *pElement, POWER_NOTIFICATION_PROC fpTimeOutProc);    
    virtual void OnPowerNotification(PPOWER_BROADCAST ppower_broadcast);

};

template <typename T>
TuPowerNotification<T>::TuPowerNotification()
:m_fpPowerNotificationProc(NULL)
,m_pElement(NULL)
{
}

template <typename T>
TuPowerNotification<T>::~TuPowerNotification()
{
}


template <typename T>
void TuPowerNotification<T>::OnPowerNotification(PPOWER_BROADCAST ppower_broadcast)
{
    if(m_fpPowerNotificationProc)
        (m_pElement->*m_fpPowerNotificationProc)(ppower_broadcast);
}

template <typename T>
void TuPowerNotification<T>::CombineElement(T *pElement, POWER_NOTIFICATION_PROC fpTimeOutProc)
{ 
    m_pElement = pElement; 
    m_fpPowerNotificationProc = fpTimeOutProc;
}

2010年1月29日 星期五

CuFileLex - 文字檔剖析

// config.sys
--------------------------------------------
TOTAL_ELEMENT_NUM   8

    ELEMENT_NUM 1
        ELEMENT_TYPE        "element"
        ELEMENT_NAME            "background"
        ELEMENT_POINT       0   0
        ELEMENT_NEEDALPHA   0
        TOTAL_PHOTO_NUM     1
            PHOTO_NAME  "media_bg.bmp" 4
        ELEMENT_END

    ELEMENT_NUM 2
        ELEMENT_TYPE        "button"
        ELEMENT_NAME            "close" 
        ELEMENT_POINT       3   3
        ELEMENT_NEEDALPHA   1
        TOTAL_PHOTO_NUM     4
            PHOTO_NAME  "close.bmp" 0
            PHOTO_NAME  "close_alpha.bmp" 1
            PHOTO_NAME  "close_down.bmp" 2
            PHOTO_NAME  "close_down_alpha.bmp" 3
        ELEMENT_END
        BUTTON_END


    ELEMENT_NUM 3
        ELEMENT_TYPE        "commandbt"
        ELEMENT_NAME            "goto-photo"        
        ELEMENT_POINT       208 85
        ELEMENT_NEEDALPHA   1
        TOTAL_PHOTO_NUM     4
            PHOTO_NAME  "photoviewer_Icon.bmp" 13
            PHOTO_NAME  "photoviewer_Icon_alpha.bmp" 14
            PHOTO_NAME  "photoviewer_animation01.bmp" 15
            PHOTO_NAME  "photoviewer_animation01_alpha.bmp" 16
        ELEMENT_END
        BUTTON_END
        COMMANDBT_ACTIVE_NAME   "photoviewv350.exe"
        COMMANDBT_END

    ELEMENT_NUM 4
        ELEMENT_TYPE        "commandbt"
        ELEMENT_NAME            "goto-music"        
        ELEMENT_POINT       14  85
        ELEMENT_NEEDALPHA   1
        TOTAL_PHOTO_NUM     4
            PHOTO_NAME  "music_Icon.bmp" 9
            PHOTO_NAME  "music_Icon_alpha.bmp" 10
            PHOTO_NAME  "music_animation01.bmp" 11
            PHOTO_NAME  "music_animation01_alpha.bmp" 12
        ELEMENT_END
        BUTTON_END
        COMMANDBT_ACTIVE_NAME   "musicv350.exe"
        COMMANDBT_END


    ELEMENT_NUM 5
        ELEMENT_TYPE        "commandbt"
        ELEMENT_NAME            "goto-video"        
        ELEMENT_POINT       113 85
        ELEMENT_NEEDALPHA   1
        TOTAL_PHOTO_NUM     4
            PHOTO_NAME  "movie_Icon.bmp" 5
            PHOTO_NAME  "movie_Icon_alpha.bmp" 6
            PHOTO_NAME  "movie_animation01.bmp" 7
            PHOTO_NAME  "movie_animation01_alpha.bmp" 8
        ELEMENT_END
        BUTTON_END
        COMMANDBT_ACTIVE_NAME   "video\videov350.exe"
        COMMANDBT_END

    ELEMENT_NUM 6
        ELEMENT_TYPE        "statictext" 
        "PhotoView"
        "text-photoview"
        208 180 98  30
        12
        255 255 255

    ELEMENT_NUM 7
        ELEMENT_TYPE        "statictext" 
        "Music"
        "text-music"
        14  180 98  30
        12
        255 255 255



    ELEMENT_NUM 8
        ELEMENT_TYPE        "statictext" 
        "Video"
        "text-Video"
        113 180 98  30
        12
        255 255 255


//




// CuFileLex.h


class CuFileLex
{
    BOOL    m_bUnicode;
    BOOL    _IsUnicodeFile();
    int     _lexw(void);
    int     _lexa(void);

    CuFile  m_File;
public:
    CuFileLex(void);
    ~CuFileLex(void);


    BOOL Open( LPCSTR lpszFileName, LPCSTR lpszOpenMode);
    virtual BOOL Open( LPCTSTR lpszFileName, LPCTSTR lpszOpenMode);

    int _type; // 最後呼叫 _lex() 的字串類型
    wstring _text; // 將讀到的字串 放到這裡

    enum {UNKNOW = 0, INTEGER = 1, FLOAT, SYMBOL, INDEX, STRING, NODE, BLOCKSTART, BLOCKEND};
    // 讀一段字 並分析字串 傳回字串類型
    int _lex(void);

    void _readInt(int &i);
    void _readInt3(int i[3]);
    void _readInt4(int i[4]);
    void _readFloat(float &f);
    void _readFloat3(float f[3]);
    void _readSymbol(wstring &str);
    void _readIndex();
    void _readString(wstring &str);
    void _readNode();
    void _readBlockStart();
    
    int _skip();

};


// CuFileLex.cpp


CuFileLex::CuFileLex(void) : _type(UNKNOW)
{

}

CuFileLex::~CuFileLex(void)
{

}

int CuFileLex::_lex(void)
{

//  static 
//  char check[] = "-0123456789._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"{}:*";
                 //"12345678901234567890123456789012345678901234567890123456789012345 678901234
                 //"0        1         2         3         4         5         6          7 
                // 1~11  = INTEGER
                // 12 = FLOAT
                // 13~65 = SYMBOL
                // 69 = INDEX
                // 66 = STRING
                // 70 = NODE  
                // 67 = BLOCKSTART
                // 68 = BLOCKEND

    // 字串分析的權位 左邊比較低 右邊比較高 
//  enum {UNKNOW = 0, INTEGER = 1, FLOAT, SYMBOL, INDEX, STRING, NODE, BLOCKSTART, BLOCKEND};

    _text = L"";

    int result;

    int current_type = 0;  
    int type = UNKNOW; // 分析字串的類型

    bool baString = false; // 當正在讀字串時 會一直讀到 下一個 '\"' 


    // 排除前置空白 換行 定位 字元
    do
    {
        result = m_File.get();
    }while( result != EOF && (result == 9 || result == 32 || result == 13 || result == 10 ));
    

    while(result != EOF)
    {

        // ---------------+---------------
        // 字串種類判段

        if( baString )
        {
            if( result == 0x22 )
                baString = !baString;

        }else if( (result >= 0x41 && result <= 0x5a) ||
                (result >= 0x61 && result <= 0x7a) ||
                (result == 0x5f) )
            current_type = SYMBOL;
        else if( (result >= 0x30 && result <= 0x39) || result == 0x2d  )
            current_type = INTEGER;
        else
        {
            switch( result )
            {
            case 0x2e:
                current_type = FLOAT;
                break;
            case 0x3a:
                current_type = INDEX;
                break;
            case 0x22:
                current_type = STRING;
                baString = !baString;
                break;
            case 0x2a:
                current_type = NODE;
                break;
            case 0x7b:
                current_type = BLOCKSTART;
                break;
            case 0x7d:
                current_type = BLOCKEND;
                break;
            default:
                {
                    _type = type;
                    return type;
                }
            }
        }
        if( type < current_type )
            type = current_type;
        // ---------------+---------------

        _text += result;
        result = m_File.get();

    }

    _type = type;

    return type;
}


int CuFileLex::_lexw(void)
{
//  static 
//  TCHAR check[] = L"-0123456789._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"{}:*";
                   //"12345678901234567890123456789012345678901234567890123456789012345 678901234
                   //"0        1         2         3         4         5         6          7 
                // 1~11  = INTEGER
                // 12 = FLOAT
                // 13~65 = SYMBOL
                // 69 = INDEX
                // 66 = STRING
                // 70 = NODE  
                // 67 = BLOCKSTART
                // 68 = BLOCKEND

    // 字串分析的權位 左邊比較低 右邊比較高 
//  enum {UNKNOW = 0, INTEGER = 1, FLOAT, SYMBOL, INDEX, STRING, NODE, BLOCKSTART, BLOCKEND};

    _text = L"";

    WORD result;

    int current_type = 0;  
    int type = UNKNOW; // 分析字串的類型

    bool baString = false; // 當正在讀字串時 會一直讀到 下一個 '\"' 

    int nSizeT = 0;

    // 排除前置空白 換行 定位 字元
    do
    {
        nSizeT = m_File.Read(&result, sizeof(result) );
    }while( nSizeT != 0 && (result != EOF && result == 9 || result == 32 || result == 13 || result == 10 ));
    

    while(result != EOF && nSizeT != 0 )
    {

        // ---------------+---------------
        // 字串種類判段

        if( baString )
        {
            if( result == 0x22 )
                baString = !baString;

        }else if( (result >= 0x41 && result <= 0x5a) ||
                (result >= 0x61 && result <= 0x7a) ||
                (result == 0x5f) )
                current_type = SYMBOL;
        else if( (result >= 0x30 && result <= 0x39) || result == 0x2d  )
            current_type = INTEGER;
        else
        {
            switch( result )
            {
            case 0x2e:
                current_type = FLOAT;
                break;
            case 0x3a:
                current_type = INDEX;
                break;
            case 0x22:
                current_type = STRING;
                baString = !baString;
                break;
            case 0x2a:
                current_type = NODE;
                break;
            case 0x7b:
                current_type = BLOCKSTART;
                break;
            case 0x7d:
                current_type = BLOCKEND;
                break;
            default:
                {
                    _type = type;
                    return type;
                }
            }
        }
        if( type < current_type )
            type = current_type;
        // ---------------+---------------

        _text += result;
        nSizeT = m_File.Read(&result, sizeof(result) );
    }

    _type = type;

    return type;
}

// 讀一段字 並分析字串 傳回字串類型
int CuFileLex::_lex(void)
{
    if( m_bUnicode )
        return _lexw();
    else
        return _lexa();

    return m_bUnicode ? _lexw() : _lexa();
}


// 讀一段字 並分析字串 傳回字串類型

void CuFileLex::_readInt(int &i)
{

    _lex();
    Assert( _type == INTEGER , L"CuFileLex::_readInt: Expected an integer\n");
    swscanf(_text.c_str(), L"%i", &i);

}

void CuFileLex::_readInt3(int i[3])
{

    _readInt(i[0]);
    _readInt(i[1]);
    _readInt(i[2]);

}

void CuFileLex::_readInt4(int i[4])
{

    _readInt(i[0]);
    _readInt(i[1]);
    _readInt(i[2]);
    _readInt(i[3]);

}

void CuFileLex::_readFloat(float &f)
{

    _lex();
    Assert( _type == FLOAT , L"CuFileLex::_readFloat: Expected an float\n");
    swscanf(_text.c_str(), L"%f", &f);

}

void CuFileLex::_readFloat3(float f[3])
{

    _readFloat(f[0]);
    _readFloat(f[1]);
    _readFloat(f[2]);

}

void CuFileLex::_readSymbol(wstring &str)
{

    _lex();
    Assert( _type == SYMBOL , L"CuFileLex::_readSymbol: Expected a symbol\n");
    str = _text;

}

void CuFileLex::_readIndex()
{

    _lex();
    Assert( _type == INDEX , L"CuFileLex::_readIndex: Expected a index\n");

}

void CuFileLex::_readString(wstring &str)
{

    _lex();
    Assert( _type == STRING , L"CuFileLex::_readString: Expected a string\n");

    // 脫溢字串兩頭的 雙引號
    if( _text.size() != 0 )
        str.assign( _text, 1, _text.size() - 2);

}
void CuFileLex::_readNode()
{

    _lex();
    Assert( _type == NODE , L"CuFileLex::_readNode: Expected a node\n");

}

void CuFileLex::_readBlockStart()
{

    _lex();
    Assert( _type == BLOCKSTART , L"CuFileLex::_readBlockStart: Expected an open brace\n");

}

int CuFileLex::_skip()
{

    int nextToken;
    int depth = 0;
    char neednext = 1;

    do {
        if(neednext) 
            nextToken = _lex();
        else 
            neednext = 1;

        if(nextToken == BLOCKSTART) 
            depth++;
        if(nextToken == BLOCKEND) 
            if(depth > 0) {
            /*printf("skipping %s\n", ASE_text);*/
            depth--;
            nextToken = _lex();
            neednext = 0;
        }
        /*printf("skipping %s (%i) (depth %i)\n", ASE_text, ASE_linenum, depth);*/
    } while(nextToken && (depth || (nextToken != NODE && nextToken != BLOCKEND)));
    /*printf("done (got %s)\n", ASE_text);*/
    return nextToken;

}

BOOL CuFileLex::_IsUnicodeFile()
{

    FILE* pFileStream = m_File.GetFILE();

    WORD result = 0;
    fseek( pFileStream, 0, SEEK_SET);
    int nSizeT = m_File.Read(&result, sizeof(result) );


    if( result != 0xfeff )
    {
        fseek( pFileStream, 0, SEEK_SET);
    }

    return (result == 0xfeff);

}
BOOL CuFileLex::Open( LPCSTR lpszFileName, LPCSTR lpszOpenMode)
{
    string strFileName = lpszFileName;
    string strOpenMode = lpszOpenMode;

    wstring wstrFileName(strFileName.begin(), strFileName.end());
    wstring wstrOpenMode(strOpenMode.begin(), strOpenMode.end());

    return Open(wstrFileName.c_str(),wstrOpenMode.c_str() );

}

BOOL CuFileLex::Open( LPCTSTR lpszFileName, LPCTSTR lpszOpenMode)
{
    

    BOOL bResult = m_File.Open(lpszFileName, lpszOpenMode);

    Assert(bResult != FALSE, L"can't open file" );
    Assert(bResult != FALSE, const_cast<TCHAR *>(lpszFileName) );

    if( bResult == FALSE )
        return FALSE;

    m_bUnicode = this->_IsUnicodeFile();

    if( m_bUnicode )
    {
        if( wcscmp (lpszOpenMode , L"r") == 0 )
        {
            lpszOpenMode = L"rb";
            m_File.Close();
            bResult = m_File.Open(lpszFileName, lpszOpenMode);
            m_bUnicode = this->_IsUnicodeFile();
        }

    }
    else
    {
        m_File.Close();
        bResult = m_File.Open(lpszFileName, lpszOpenMode);
        
    }

    return bResult;
}


從某一隻ASE檔載入器中抓出來的,
CuFileLex 跟CuStringList 相比, 能載入較多格式的文字串, 組合後可以使用更豐富的設定檔
上面有兩大段分別支援一般文字檔跟UNICODE文字檔, 很顯示需要重構! 現在沒打算重構!
重構時間點在何時呢? 在他出錯的時後, 或是下次程式碼"review"的時後!

2010年1月28日 星期四

CuMicroTime - the current timestamp with microseconds.

// the current timestamp with microseconds.



// CuMicroTime.php 


class CuMicroTime  {

    var $usec;
    var $sec;
    
    function CuMicroTime(/* CuMicroTime */ $MicroTime = null) {

        if( $this->CheckClassType($MicroTime) )
        {
            $this->usec = $MicroTime->usec;
            $this->sec = $MicroTime->sec;
        }
        else
        {
            list($this->usec, $this->sec) = explode(" ", microtime());
        }
    }
    
    function Dec( /* CuMicroTime */ $MicroTime)
    {
        
        if( CheckClassType($MicroTime) )
            return NULL;

        $usec = (float)$this->usec - (float)$MicroTime->usec;
        $sec = $this->sec - $MicroTime->sec;

        $usec = substr($usec, 1);
        return $sec.$usec;
        
    }
    
    function CheckClassType($MicroTime)
    {
        if( gettype($MicroTime) != 'object' || get_class($MicroTime) != "cumicrotime" )
            return false;
        else
            return true;
    }
    
    
}

2010年1月27日 星期三

CuShellExecuteEx - Performs an operation on a specified file.

// Performs an operation on a specified file.



// CuShellExecuteEx.h

class CuShellExecuteEx  
{

public:
    void SetExecuteFile(wstring strFile, BOOL bAutoModuleFile = FALSE);
    BOOL OnShellExecuteEx();

    SHELLEXECUTEINFO m_sei;
    wstring m_strExecuteFile;

    CuShellExecuteEx();
    ~CuShellExecuteEx();

};


// CuShellExecuteEx.cpp

CuShellExecuteEx::CuShellExecuteEx()
{
    m_sei.cbSize = sizeof(SHELLEXECUTEINFO);
    m_sei.fMask = 0;
    m_sei.hwnd = NULL;
    m_sei.lpVerb = TEXT("open");
    m_sei.lpFile = NULL;
    m_sei.lpParameters = NULL;
    m_sei.lpDirectory = NULL;
    m_sei.nShow = SW_SHOW;
    m_sei.hInstApp = NULL;
}

CuShellExecuteEx::~CuShellExecuteEx()
{

}

BOOL CuShellExecuteEx::OnShellExecuteEx()
{
    return ::ShellExecuteEx(&m_sei);
}

void CuShellExecuteEx::SetExecuteFile(wstring strFile, BOOL bAutoModuleFile /*= FALSE*/)
{

    if( bAutoModuleFile )
    {
        CuModuleFile mf;
        strFile = mf.GetModuleFileName(strFile);
    }

    m_strExecuteFile = strFile;
    m_sei.lpFile = m_strExecuteFile.c_str();

}

2010年1月26日 星期二

CuModuleFile - Retrieves the fully-qualified path for the file that contains the onwer module.

// Retrieves the fully-qualified path for the file that contains the onwer module.



// CuModuleFile.h

class CuModuleFile //: public IuModuleFile
{
public:
    CuModuleFile();
    ~CuModuleFile();


    wstring GetModuleFileName(wstring strFileName);

   // 傳入空的字串 會傳回執行檔檔名
    wstring GetUnModuleFileName(wstring strFileName = L""); 
    wstring CutRFind(wstring str, TCHAR ch);

};



// CuModuleFile.cpp


CuModuleFile::CuModuleFile()
{

}

CuModuleFile::~CuModuleFile()
{

}


//////////////////////////////////////////////////////////////////////
// 函式名稱:GetModuleFileName
// 函式說明:將strFileName 前面加上 主執行緒執行檔同目錄的路徑
// 使用範例:
// 啟動 C:\Documents and Settings\Eric Wang\My Documents\Work\test.exe
// strFileName = L"sample.ini"
// str = mf.GetModuleFileName(strFileName);
// Access(str = L"C:\Documents and Settings\Eric Wang\My Documents\Work\sample.ini");
//////////////////////////////////////////////////////////////////////
wstring CuModuleFile::GetModuleFileName(wstring strFileName)
{

    wstring filename;
    wstring strFile = strFileName;

    wstring::size_type npos = -1;
    wstring::size_type indexCh1a;

    int nCount = 0;
    while   ( (indexCh1a = strFile.find(L"..\\")) != npos )
    {
        nCount++;
        strFile = strFile.substr(indexCh1a + 3);
    }

    TCHAR szModule[255] = L"";
    LPTSTR psz;

    ::GetModuleFileName(GetModuleHandle(NULL), szModule, MAX_PATH);

    do
    {
        psz = wcsrchr(szModule, L'\\');
        if (psz)
        {
            *psz = L'\0';
        }
    }while( nCount-- );

    wcscat(szModule, L"\\");
    wcscat(szModule, strFile.c_str());

    return szModule;    
}


//////////////////////////////////////////////////////////////////////
// 函式名稱:GetUnModuleFileName
// 函式說明:函路徑的檔名前面的路徑清掉, strFileName = NULL 時 會傳回主執行緒的執行檔檔名
// 使用範例:
// strFileName = L"C:\\Documents and Settings\\Eric Wang\My Documents\\Work\\temp.txt"
// str = mf.GetUnModuleFileName(strFileName);
// Access(str = L"temp.txt");
//////////////////////////////////////////////////////////////////////
wstring CuModuleFile::GetUnModuleFileName(wstring strFileName /* = L"" */)
{


    wstring filename;
    wstring strFull;
    
    if( strFileName.size() == 0 )
    {
        TCHAR szModule[255] = L"";
        ::GetModuleFileName(GetModuleHandle(NULL), szModule, MAX_PATH);
        strFull = szModule;
    }
    else
        strFull = strFileName;

    static const wstring::size_type npos = -1;


    wstring::size_type indexCh1a;
    indexCh1a = strFull.rfind('\\');

    if( indexCh1a != npos )
        filename = strFull.substr(indexCh1a + 1);
    else
        filename = strFull;

    return filename;


}


//////////////////////////////////////////////////////////////////////
// 函式名稱: CutRFind
// 函式說明: 去掉 ch 右邊的字串
// 使用範例: 
// str = text.txt
// str2 = mf.GetRFind(str, '.');
// Assert( str2 = L"text");
//////////////////////////////////////////////////////////////////////
wstring CuModuleFile::CutRFind(wstring str, TCHAR ch)
{

    wstring strResult;
    static const wstring::size_type npos = -1;
    wstring::size_type indexCh1a;
    indexCh1a = str.rfind(ch);

    if( indexCh1a != npos )
        strResult = str.substr(0, indexCh1a);
    else
        strResult = str;

    return strResult;

}

2010年1月25日 星期一

CuVolume - sets the volume of a waveform output device.

// sets the volume of a waveform output device.


DWORD dw, dw2;
// dw : 0x0000~0xffff
// dw2: 0~MAX

CuVolume Volume;
dw = Volume.GetVolume();
dw2 = Volume.GetVolume(MAX);

Volume.SetVolume(dw);
Volume.SetVolume(dw2, MAX);

Volume.IncVolume(MAX);
Volume.DecVolume(MAX);



// CuVolume.h

class CuVolume  
{
    BOOL    m_bMute;
    unsigned long   m_nVolume;

    //////////////////////////////////////////////////////////////////////
    // 
    CuDllManager dll;
    typedef DWORD (*pAudio)  ();
    pAudio pProc;

    void UpdateVolumeFromRegistry();
    //////////////////////////////////////////////////////////////////////

public:
    CuVolume();
    virtual ~CuVolume();

    void IncVolume(int nMax);
    void DecVolume(int nMax);

    BOOL GetMute(void){ return m_bMute; }
    BOOL SetMute(BOOL b);

    // 直接指定值 v = 0 ~ 0xffff
    BOOL SetVolume(unsigned long v);
    unsigned long GetVolume(void);

    // 正規化過的值  指定max  Ex: v = 50 , nMAx = 100 , 會設定 50%
    // v = 1, nMax = 5, 會設定 20%
    BOOL SetVolume(int v, int nMax);

    // 取回正規化過的值
    int GetVolume(int nMax);
};


// CuVolume.cpp

#define MAX_VALUES 0xffff

void CuVolume::UpdateVolumeFromRegistry()
{
    if( pProc )
        pProc();
}


CuVolume::CuVolume()
:m_bMute(FALSE)
{
    GetVolume();

    dll.LoadLibrary(_T("coredll.dll"));
    pProc = (pAudio)dll.GetProcAddress(_T("AudioUpdateFromRegistry"));

}

CuVolume::~CuVolume()
{
}

BOOL CuVolume::SetMute(BOOL b)
{

    static unsigned long nVolume = GetVolume();

    m_bMute = b;
    if (m_bMute)
    {
        nVolume = GetVolume();
        SetVolume(0);
    }
    else
    {
        SetVolume(nVolume);
    }

    return TRUE;

}

BOOL CuVolume::SetVolume(unsigned long v)
{

    m_nVolume = v;
    waveOutSetVolume(NULL, 0x10001 * v) ;

    CReg reg(HKEY_CURRENT_USER, _T("ControlPanel\\Volume"));
    reg.SetDW(_T("Volume"), 0x10001 * v);

    UpdateVolumeFromRegistry();

    return TRUE;
}

unsigned long CuVolume::GetVolume(void)
{

    unsigned long Value;
    if (waveOutGetVolume(NULL,&Value) == MMSYSERR_NOERROR)
    {
        m_nVolume = ( (LOWORD(Value)+HIWORD(Value)) ) / 2 ;
    }
    return m_nVolume;

}

BOOL CuVolume::SetVolume(int v, int nMax)
{

    DWORD Value = v * MAX_VALUES / nMax;
    SetVolume(Value);

    return TRUE;

}

int CuVolume::GetVolume(int nMax)
{
    unsigned long Value;
    Value = (float)nMax * ((float)GetVolume() + 600) / (float)MAX_VALUES;
    return Value;
}

void CuVolume::IncVolume(int nMax)
{
    
    if( GetMute() )
        SetMute(FALSE);

    unsigned long offset_Value = (float)MAX_VALUES / nMax;
    unsigned long Value = (float)GetVolume();

    Value += offset_Value;
    if( Value > MAX_VALUES)
        Value = MAX_VALUES;

    SetVolume(Value);

}
void CuVolume::DecVolume(int nMax)
{

    if( GetMute() )
        SetMute(FALSE);

    float offset_Value = (float)MAX_VALUES / nMax;
    float Value = (float)GetVolume();

    if( Value <= offset_Value)
        Value = 0;
    else
        Value -= offset_Value;

    SetVolume(Value);

}

2010年1月24日 星期日

CuPowerNotification - to register for power notification events.

// to register for power notification events.



// CuPowerNotification.h


class CuPowerNotification  
{
    HANDLE m_hRequestPowerNotifications;

    CuWinThread *m_pWinThread;

    CuMsgQueue m_MsgQueue;

public:
    virtual void OnPowerNotification(PPOWER_BROADCAST ppower_broadcast){};
    BOOL StopPowerNotifications();
    HANDLE RequestPowerNotifications(DWORD Flags = POWER_NOTIFY_ALL, wstring strMsgQueueName = L"");
    CuPowerNotification();
    virtual ~CuPowerNotification();


private:
    static DWORD Process(LPVOID lpVoid);

};


// CuPowerNotification.cpp


#define QUEUE_ENTRIES 3
#define QUEUE_SIZE ( QUEUE_ENTRIES * (sizeof(POWER_BROADCAST) + sizeof(POWER_BROADCAST_POWER_INFO)) )
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CuPowerNotification::CuPowerNotification()
:m_hRequestPowerNotifications(NULL)
,m_pWinThread(NULL)

{

}

CuPowerNotification::~CuPowerNotification()
{
    StopPowerNotifications();
}

HANDLE CuPowerNotification::RequestPowerNotifications(
DWORD Flags /* = POWER_NOTIFY_ALL */
, wstring strMsgQueueName /*= L""*/)
{

    StopPowerNotifications();

    MSGQUEUEOPTIONS MsgQueueOptions;

    memset(&MsgQueueOptions , 0, sizeof( MsgQueueOptions));
    
    MsgQueueOptions.dwSize = sizeof( MSGQUEUEOPTIONS );
    MsgQueueOptions.dwFlags = 0  ;
    MsgQueueOptions.dwMaxMessages = QUEUE_ENTRIES;
    MsgQueueOptions.cbMaxMessage =  QUEUE_SIZE;
    MsgQueueOptions.bReadAccess = TRUE ;
    //TCHAR *pszMsgQueue = strMsgQueueName.c_str();
    TCHAR szMsgQueueName[64] = L"";

    if( strMsgQueueName.empty() )
        wsprintf( szMsgQueueName, L"%x", (int)this );
    else
        wsprintf( szMsgQueueName, L"%s", strMsgQueueName.c_str());
    m_MsgQueue.CreateMsgQueue(szMsgQueueName, &MsgQueueOptions);

    m_hRequestPowerNotifications = ::RequestPowerNotifications(  m_MsgQueue, Flags );

    if( m_hRequestPowerNotifications )
        m_pWinThread = _BeginThread((_THREADPROC)CuPowerNotification::Process,
          (LPVOID)this);

    return m_hRequestPowerNotifications;

}

BOOL CuPowerNotification::StopPowerNotifications()
{

    if( m_pWinThread )
        m_pWinThread->Delete();

    m_pWinThread = NULL;

    return ::StopPowerNotifications(m_hRequestPowerNotifications);
}


DWORD CuPowerNotification::Process(LPVOID lpVoid)
{
    CuPowerNotification *pPowerNotification = (CuPowerNotification *)lpVoid;

    static BYTE buf[QUEUE_SIZE];
    static unsigned long nRead = 0;
    static unsigned long flags = 0;
    
    DWORD dwResult;
    while(1)
    {
        dwResult = WaitForSingleObject(pPowerNotification->m_MsgQueue, INFINITE);
        if( dwResult == WAIT_OBJECT_0 )
        {
            memset(&buf , 0, QUEUE_SIZE);
            dwResult = pPowerNotification->m_MsgQueue.ReadMsgQueue( 
            &buf, QUEUE_SIZE, &nRead, INFINITE, &flags);
            if( dwResult != FALSE )
                pPowerNotification->OnPowerNotification((PPOWER_BROADCAST)buf);
        }
    }

    return 0;
}

2010年1月23日 星期六

TuWinTimer - creates a timer with the specified time-out value.

// creates a timer with the specified time-out value.



class CuMyClass
{
    TuWinTimer<CuMyClass> m_winTimer;

public:

    void OnMyFunction(void);
    void Init(void);

};

void CuMyClass::Init()
{
    m_winTimer.Init(1000); 
    m_winTimer.CombineElement(this, &CuMyClass::OnMyFunction, g_hWnd);

    ...
    m_winTimer.OnStardTime();
}

void CuMyClass::OnMyFunction(void)
{
    ...
    m_winTimer.OnStopTime();
}


// TuWinTimer.h

template <typename T>
class TuWinTimer 
    
    UINT m_uElapse;

    T *m_pElement;

    HWND m_hWnd;

    typedef void ( T::*ELEMENTTIME_TIMEOUTPROC)(void);
    ELEMENTTIME_TIMEOUTPROC m_fpTimeOutProc;


    static VOID CALLBACK TuWinTimerTimerProc( HWND hwnd,
        UINT uMsg,
        UINT_PTR idEvent,
        DWORD dwTime
    )
    {

        TuWinTimer<T> *pElement = (TuWinTimer<T>*)idEvent;
        T *pActiveElement = pElement->m_pElement;
        (pActiveElement->*(pElement->m_fpTimeOutProc))();

    }
public:
    
    TuWinTimer();
    ~TuWinTimer();

    void Init(UINT uElapse);
    void CombineElement(T *pElement, ELEMENTTIME_TIMEOUTPROC fpTimeOutProc, HWND hWnd);

    void OnStardTime();
    void OnStopTime();

};




template <typename T>
TuWinTimer<T>::TuWinTimer()
:m_uElapse(0)
,m_pElement(NULL)
,m_fpTimeOutProc(NULL)
,m_hWnd(NULL)
{
}

template <typename T>
TuWinTimer<T>::~TuWinTimer()
{
    OnStopTime();
}

template <typename T>
void TuWinTimer<T>::Init(UINT uElapse)
{
    m_uElapse = uElapse;
}

template <typename T>
void TuWinTimer<T>::OnStardTime()
{

    OnStopTime();
    ::SetTimer(m_hWnd, (UINT)this, m_uElapse, TuWinTimer<T>::TuWinTimerTimerProc );

}
template <typename T>
void TuWinTimer<T>::OnStopTime()
{
    ::KillTimer(m_hWnd, (UINT)this);
}


template <typename T>
void TuWinTimer<T>::CombineElement(T *pElement, ELEMENTTIME_TIMEOUTPROC fpTimeOutProc, HWND hWnd)
{ 
    m_pElement = pElement; 
    m_fpTimeOutProc = fpTimeOutProc;

    Assert( hWnd != NULL , L"Error : hWnd == NULL");
    m_hWnd = hWnd;
}

2010年1月22日 星期五

CuMsgQueue - pass information between different programs.

// pass information between different programs.

//

MSGQUEUEOPTIONS msg_queue_options;

msg_queue_options.dwSize    = sizeof(MSGQUEUEOPTIONS);
msg_queue_options.dwMaxMessages    = 0;
msg_queue_options.cbMaxMessage    = TEST_BUFFER_SIZE;
msg_queue_options.bReadAccess    = TRUE;
msg_queue_options.dwFlags    = MSGQUEUE_NOPRECOMMIT;

MsgReadQueue.CreateMsgQueue(lpszName, &msg_queue_options);

//

wchar_t test_text[TEST_BUFFER_SIZE];
ret = WaitForSingleObject(MsgReadQueue, INFINITE);
 

if (ret == WAIT_OBJECT_0) {
        DWORD    read_bytes;
        DWORD    flag;

        MsgReadQueue.ReadMsgQueue(test_text, sizeof(wchar_t) * TEST_BUFFER_SIZE, &read_bytes, INFINITE, &flag);
}


// CuMsgQueue.h


class CuMsgQueue  
{
    HANDLE m_hCreateMsgQueue;

public:
    BOOL ReadMsgQueue(LPVOID lpBuffer,
                        DWORD cbBufferSize,
                        LPDWORD lpNumberOfBytesRead,
                        DWORD dwTimeout,
                        DWORD* pdwFlags);
    HANDLE CreateMsgQueue(LPWSTR lpszName,LPMSGQUEUEOPTIONS lpOptions);
    BOOL CloseMsgQueue(  );
    operator HANDLE() const;


    CuMsgQueue();
    virtual ~CuMsgQueue();

};


// CuMsgQueue.cpp


CuMsgQueue::CuMsgQueue()
:m_hCreateMsgQueue(NULL)
{

}

CuMsgQueue::~CuMsgQueue()
{
    CloseMsgQueue();
}

BOOL CuMsgQueue::CloseMsgQueue()
{
    return ::CloseMsgQueue(m_hCreateMsgQueue);
}

HANDLE CuMsgQueue::CreateMsgQueue(LPWSTR lpszName, LPMSGQUEUEOPTIONS lpOptions)
{

    CloseMsgQueue();
    m_hCreateMsgQueue = ::CreateMsgQueue(lpszName, lpOptions);
    return m_hCreateMsgQueue;
}

CuMsgQueue::operator HANDLE() const
    { return (HANDLE)(this == NULL ? NULL : m_hCreateMsgQueue); }

BOOL CuMsgQueue::ReadMsgQueue(LPVOID lpBuffer,
                        DWORD cbBufferSize,
                        LPDWORD lpNumberOfBytesRead,
                        DWORD dwTimeout,
                        DWORD* pdwFlags)
{
    return ::ReadMsgQueue(m_hCreateMsgQueue, lpBuffer, cbBufferSize, lpNumberOfBytesRead, dwTimeout, pdwFlags);
}


像這種 MSGQUEUEOPTIONS msg_queue_options; 有結構設定的部份, 實在很想把他包到類別裡, 在使用函式參數傳遞,並且設定部份參數為預設值!

不僅使用起來美觀! 而且還不用特別去查結構!

2010年1月21日 星期四

CuTimer - specialized type of clock.

// specialized type of clock. 


CuTimer _Timer;

while(1)
{
    _Timer.Make_Tick_Data();

    if( _Timer.GetTimeOut(9) )
        ....

    _Timer.Tick_Data_Clear();
}

// CuTimer.h

class CuTimer
{

public:
    BOOL GetTimeOut(int i); // table_1

    void Make_Tick_Data();
    void Tick_Data_Full();
    void Tick_Data_Clear();
    CuTimer();
    ~CuTimer();

private:
    DWORD More_Time[20];
    DWORD lastTickCount[20];
    BYTE Time_move[20];
    DWORD thisTickCount;

};



// CuTimer.cpp


CuTimer::CuTimer(void)
{

    this->Tick_Data_Clear();

}

CuTimer::~CuTimer(void)
{
}


void CuTimer::Tick_Data_Clear()
{
    memset( Time_move, 0, sizeof Time_move );
}

void CuTimer::Tick_Data_Full()
{
    memset( Time_move, 1, sizeof Time_move );
}

void CuTimer::Make_Tick_Data()
{
    static DWORD delay[20] = {
          10,     //0 , 1/100 sec 0.01
          16,     //1 , 1/60  sec 0.016
          17,     //2 , 1/56  sec 0.017
          20,     //3 , 1/48  sec 0.020
          25,     //4 , 1/40  sec 0.025
          33,     //5 , 1/30  sec 0.033
          41,     //6 , 1/24  sec 0.041
          62,     //7 , 1/16  sec 0.062
          83,     //8 , 1/12  sec 0.083
          125,    //9 , 1/8   sec 0.125
          166,    //10, 1/6   sec 0.166
          250,    //11, 1/4   sec 0.250
          333,    //12, 1/3   sec 0.333
          500,    //13, 1/2   sec 0.5
          1000,   //14, 1     sec
          2000,   //15, 2     sec
          3000,   //16, 3     sec
          4000,   //17, 4     sec
          5000,   //18, 5     sec
          8000    //19, 8     sec
        };

    thisTickCount = GetTickCount();
    for (int i = 0; i < 20;  i++)
    {
        if( (thisTickCount - lastTickCount[i]) >= delay[i])
        {
        More_Time[i] = (thisTickCount - lastTickCount[i]) - delay[i];

        lastTickCount[i] = thisTickCount;

        if( More_Time[i] < 30 )
          lastTickCount[i] -= More_Time[i];

        Time_move[i]++;
        }
    }
}

BOOL CuTimer::GetTimeOut(int i)
{
    return (BOOL)Time_move[i];
}

2010年1月20日 星期三

PHP : CDate

// CDate.php

class CDate {
    
    function str2time($strStr, $strPattern)
    {
        

       // an array of the valide date characters, see: http://php.net/date#AEN21898
       $arrCharacters = array(
           'd', // day
           'm', // month
           'y', // year, 2 digits
           'Y', // year, 4 digits
           'H', // hours
           'i', // minutes
           's'  // seconds
       );
       // transform the characters array to a string
       $strCharacters = implode('', $arrCharacters);


    
       // splits up the pattern by the date characters to get an array of the delimiters between the date characters
       $arrDelimiters = preg_split('~['.$strCharacters.']~', $strPattern);

       // transform the delimiters array to a string
       $strDelimiters = quotemeta(implode('', array_unique($arrDelimiters)));


    
       // splits up the date by the delimiters to get an array of the declaration
       $arrStr    = preg_split('~[' . $strDelimiters . ']~' , $strStr);
    

       // splits up the pattern by the delimiters to get an array of the used characters
       $arrPattern = preg_split('~['.$strDelimiters.']~', $strPattern);
    
        
       // if the numbers of the two array are not the same, return false, because the cannot belong together
       if (count($arrStr) !== count($arrPattern)) {
           return false;
       }
    
       // creates a new array which has the keys from the $arrPattern array and the values from the $arrStr array
       $arrTime = array();
       for ($i = 0;$i < count($arrStr);$i++) {
           $arrTime[$arrPattern[$i]] = $arrStr[$i];
       }
    
            
       // gernerates a 4 digit year declaration of a 2 digit one by using the current year
       if (isset($arrTime['y']) && !isset($arrTime['Y'])) {
           $arrTime['Y'] = substr(date('Y'), 0, 2) . $arrTime['y'];
       }
    
    
       // if a declaration is empty, it will be filled with the current date declaration
       foreach ($arrCharacters as $strCharacter) {
           if (empty($arrTime[$strCharacter])) {
               $arrTime[$strCharacter] = date($strCharacter);
           }
       }
    
    
       // checks if the date is a valide date
       if (!checkdate($arrTime['m'], $arrTime['d'], $arrTime['Y'])) {
           return false;
       }
    
       // generates the timestamp
       $intTime = mktime($arrTime['H'], $arrTime['i'], $arrTime['s'], $arrTime['m'], $arrTime['d'], $arrTime['Y']);
       // returns the timestamp
    
       return $intTime;
    } // end function str2time
    
}// end class CDate


雖然現在很少人在寫PHP用手動比對時間, 通常都交給SQL去驗證.

2010年1月19日 星期二

Assert - assertion

// An assertion statement specifies a condition that you expect to hold true at some particular point in your program.

Assert(m_hThread != NULL, _T("CuWinThread::ResumeThread m_hThread != NULL");

// uAssert.h


#if defined(_DEBUG)


    #define WIDEN2(x) L ## x
    #define WIDEN(x) WIDEN2(x)
    #define __WFILE__ WIDEN(__FILE__)

    extern bool CustomAssertFunction( bool, TCHAR*, int, TCHAR*, bool*);

    #if defined(_WINDOWS)
    #define ASSERTPRESS { _asm { int 3 } }
    #else
    #define ASSERTPRESS {}
    #endif // defined(_WINDOWS)


    #define Assert( exp, description) \
    { static bool ignoreAlways = false; \
        if( !ignoreAlways) { \
            if( CustomAssertFunction( (int)(exp), description, __LINE__, __FILE__, &ignoreAlways) ) \
                ASSERTPRESS \
        } \
    }

    #define Verify(exp, description)          Assert(exp, description)


#else

    #define Assert(exp, description)    ((void)0)
    #define Verify(exp, description)    ((void)(exp))

#endif  // defined(_DEBUG)




// uAssert.cpp



// Return:
// true - Stop On Assert Line
// false - continue
bool CustomAssertFunction( bool bExp, TCHAR* strDesc, int iLine, TCHAR* strFilename,  bool *ignoreAlways)
{

    if( !bExp )
    {
        TCHAR strTitle[255] = TEXT("");
        TCHAR strText[255] = TEXT("");
        wsprintf(strTitle, TEXT("%s - %d"), strFilename, iLine);
        wsprintf(strText, TEXT("%s \n Yes to Continue \n No to Break\n Cancle to Ignore Always"), strDesc);
        int nRelease = MessageBox(NULL, strText, strTitle, MB_YESNOCANCEL);
        switch( nRelease )
        {
        case 6:
            return false;
            break;
        case 7:
            return true;
            break;
        case 2:
            *ignoreAlways = true;
            break;
        }
    }
        
    return false;

}
這個有擴充過, 使用 _asm { int 3 } 能停在Assert 那一行.

2010年1月18日 星期一

CuSocketFile - A CuFile object used for sending and receiving data across a network via Windows Sockets

// CuSocketFile - A CuFile object used for sending and receiving data across a network via Windows Sockets.

CuSocket sk;
CuSocketFile skFile(&sk);

CuFile *pFile = &skFile;

pFile->Write(...);
pFile->Read(...);



// CuSocketFile.h

class CuSocketFile : public CuFile  
{
    CuSocket* m_pSocket;

public:

    CuSocketFile( CuSocket* pSocket);
    ~CuSocketFile();

public:
    virtual int Write(const void* lpBuf, UINT nCount);
    virtual int Read(void* lpBuf, UINT nCount);

};



// CuSocketFile.cpp

CuSocketFile::~CuSocketFile()
{

}

CuSocketFile::CuSocketFile(CuSocket *pSocket)
{

    m_pSocket = pSocket;

}

// rc == SOCKET_ERROR 在外部在處理
int CuSocketFile::Read(void *lpBuf, UINT nCount)
{

    if( lpBuf == NULL ) 
        return 0;

    return m_pSocket->Receive(lpBuf, nCount, 0);

}

int CuSocketFile::Write(const void *lpBuf, UINT nCount)
{

    if( lpBuf == NULL ) 
        return 0;
        
    retrun m_pSocket->Send((const TCHAR*)lpBuf , nCount, 0);

}
使用繼承 public CuFile , 在對TheApp做多型, TheApp並不需要知道是LocalFile 還是 Remote Socket.
這裡有個很特別的問題, CuFile 跟 CuSocketFile 除了介面相同外, 並沒有任何的程式碼相容.
因此需要繼承的並不是CuFile實體, 而是
class CuFile : public IuFile
class CuSocketFile : public IuFile
繼承 CuFile 的介面 IuFile

2010年1月17日 星期日

CuTestUnit - Easy way to Unit Test.

// Easy way to Unit Test.



// CuTestUnit.php

class CuTestUnit
{
    var $debug;
    
    function __construct()
    {
        $this->debug = new CuDebugger; 
    }   
    
    function CuTestUnit()
    {
        $this->__construct();
    }
    
    function assertTrue($bool, $key = null )
    {
        if( !$bool || $bool != true)
            $result = "<font color = '#ff0000'>FALSE</font>";
        else
            $result = "<font color = '#0000ff'>OK</font>";
        
        $this->debug->debug($result,  $key);  
    }
    
    function assertEquals($value1, $value2, $key = null)
    {
        $this->assertTrue($value1 == $value2, $key);
    }
    
    function GetHTML()
    {
        return $this->debug->GetHTML();
    }
    
}

2010年1月16日 星期六

TuDeck - Card stack

//   Card stack


// u_TDeck.pas

unit u_TDeck;
interface
uses
        Windows, Classes, SysUtils,
        StdCtrls,
        ch_LogMessages,

        u_TList,
        u_TexasHoldConst;

const

        CARD_LIMIT = (13 * 4);    // 撲克牌總數 十三張 * 4種類

        // 牌的位置
        POSITION_POOL = 0; // 在牌堆裡
        POSITION_HOLE = 1; // 玩家手牌
        POSITION_FIELD = 2;// 桌上公牌

        // 牌的類型
        CARD_CATEGORY_SPADE = 0;  // 黑桃
        CARD_CATEGORY_HEARD = 1;  // 紅心
        CARD_CATEGORY_CLUB = 2;  // 梅花
        CARD_CATEGORY_DIAMOND = 3;  // 方塊
        CARD_CATEGORY_LIMIT = 4;  //

type

//******************************************************************************
// 類別名稱:TCardData
// 功  能:每張牌的結構定義
//******************************************************************************
        TCardData = class        //TCardData 結構的定義
            Category: word;       // 種類                 
            Index: word;          // 數
            ListIndex: word;      // 表格位置
            Position: word;       // 位置
            Player: integer;      // 玩家
        end;

//******************************************************************************
// 類別名稱:TuDeck
// 功  能:維護牌堆資料 提供 亂數取牌
//******************************************************************************
        TuDeck = Class
          private
            m_aCardDataList: TuList;  // 撲克牌陣列
            m_DeckMessToFiles : TLogMessToFiles;
            function GetRandomCardIndex: integer; // 找一張沒有被派發出來的牌
          public
            constructor Create;
            destructor Destroy; override;

            procedure Init; // 初始化

            
            function GetRandomCard(Player, nPosition: integer): integer;
            function GetIndexCard(nIndex,Player, nPosition:integer):integer;

            function Items( nListIndex:integer ):TCardData;
            function Index( nListIndex:integer ): word;
            function Category( nListIndex:integer ): word;
            function Position( nListIndex:integer ): word;
            function Player( nListIndex:integer ): integer;
        end;
        function compareByPoker(Item1 : Pointer; Item2 : Pointer) : Integer;


implementation


constructor TuDeck.Create;
var
        i: integer;
        TmpCardData: TCardData;
begin
        m_DeckMessToFiles := TLogMessToFiles.Create('DeckMessage.txt');
 
        m_aCardDataList := TuList.Create();
        for i := 0 to CARD_LIMIT - 1 do begin
            TmpCardData := TCardData.Create();
            m_aCardDataList.Add(TmpCardData);
        end;
        
        Init();
end;


destructor TuDeck.Destroy;
begin
        m_aCardDataList.Free;
        m_DeckMessToFiles.Free;
end;


//******************************************************************************
// 函式名稱:Init
// 功  能:初始化撲克牌陣列 並洗牌(重設亂數種子)
//******************************************************************************
procedure TuDeck.Init();
var

        TmpCategory: integer;
        TmpIndex: integer;
        CardIndex: integer;
        TmpCardData : TCardData;
begin

        // 每一把要重新洗牌 重設亂數種子
        Randomize;

        CardIndex := 0;
        for TmpCategory := 0 to CARD_CATEGORY_LIMIT - 1 do begin
            for TmpIndex := 1 to CARD_INDEX_LIMIT do begin
                TmpCardData := m_aCardDataList.GetItems(CardIndex);
                TmpCardData.Category := TmpCategory;
                TmpCardData.Index := TmpIndex;
                TmpCardData.ListIndex := CardIndex;
                TmpCardData.Position := POSITION_POOL;
                TmpCardData.Player := PLAYER_NIL;
                Inc(CardIndex);
            end;
        end;
end;


//******************************************************************************
// 函式名稱:GetIndexCard
// 功  能:直接取出 nIndex 指定的牌
//******************************************************************************
function TuDeck.GetIndexCard(nIndex,Player, nPosition:integer):integer;
var
        TmpCardData : TCardData;
begin
        TmpCardData := m_aCardDataList.GetItems(nIndex);
        TmpCardData.Position := nPosition;
        TmpCardData.Player := Player;

        Result := nIndex;
end;


//******************************************************************************
// 函式名稱:GetRandomCard
// 功  能:亂數取牌
//******************************************************************************
function TuDeck.GetRandomCard(Player, nPosition: integer): integer;
var
        nIndex: integer;
        TmpCardData : TCardData;
begin

        nIndex := GetRandomCardIndex();
        TmpCardData := m_aCardDataList.GetItems(nIndex);
        TmpCardData.Position := nPosition;
        TmpCardData.Player := Player;

        Result := nIndex;
end;


//******************************************************************************
// 函式名稱:GetRandomCardIndex
// 功  能:隨機取得 CardList 的參數
//******************************************************************************
function TuDeck.GetRandomCardIndex: integer;
var
        TmpIndex, nIndex: integer;


        nTmpNext : Integer;
        nTmpPrev : Integer;
        nRandom2 : Integer;

        TmpCardData : TCardData;
begin


        nIndex := Random(CARD_LIMIT);

        // 如果 還沒發出去就直接發
        TmpCardData := m_aCardDataList.GetItems(nIndex);
        if TmpCardData.Position = POSITION_POOL then
        begin
            Result := nIndex;
            exit;
        end;

        if nIndex = CARD_LIMIT - 1 then begin
            nIndex := 0;
        end;

        (* 順序搜尋 *)
        nTmpNext := -1;
        for TmpIndex := nIndex to CARD_LIMIT - 1 do begin
            TmpCardData := m_aCardDataList.GetItems(TmpIndex);
            if TmpCardData.Position = POSITION_POOL then
            begin
                nTmpNext := TmpIndex;
                break;
            end;
        end;
        
        if nIndex = 0 then begin
            nIndex := CARD_LIMIT - 1;
        end;

        nTmpPrev := -1;
        for TmpIndex := nIndex downto 0 do begin
            TmpCardData := m_aCardDataList.GetItems(TmpIndex);
            if TmpCardData.Position = POSITION_POOL then begin
                nTmpPrev := TmpIndex;
                break;
            end;
        end;

        // 當所有牌都發完時 才會兩個都是負的
        // 如果發到都沒有牌 代表程式有問題
        if (nTmpNext = -1) And (nTmpPrev = -1) then begin
            m_DeckMessToFiles.m_WriteTXTOne(
            Format ('nIndex %d nTmpNext %d nTmpPrev %d ',[nIndex, nTmpNext, nTmpPrev]), 1);
        end;

        if nTmpNext = -1 then begin
            Result := nTmpPrev;
            exit;
        end;

        if nTmpPrev = -1 then begin
            Result := nTmpNext;
            exit;
        end;


        nRandom2 := Random(CARD_LIMIT) mod 2;
        if nRandom2 = 1 then begin
            Result := nTmpNext;
        end else begin
            Result := nTmpPrev;
        end;

end;

function TuDeck.Index( nListIndex:integer ): word;
begin
        Result := TCardData(m_aCardDataList.GetItems(nListIndex)).Index;
end;

function TuDeck.Category( nListIndex:integer ): word;
begin
       Result := TCardData(m_aCardDataList.GetItems(nListIndex)).Category;
end;

function TuDeck.Player( nListIndex:integer ): integer;
begin
       Result := TCardData(m_aCardDataList.GetItems(nListIndex)).Player;
end;

function TuDeck.Position( nListIndex:integer ): word;
begin
       Result := TCardData(m_aCardDataList.GetItems(nListIndex)).Position;
end;

function TuDeck.Items( nListIndex:integer ): TCardData;
begin
        Result := m_aCardDataList.GetItems(nListIndex);
end;

end.



function compareByPoker(Item1 : Pointer; Item2 : Pointer) : Integer;
var
        CardData1, CardData2: TCardData;
begin
        CardData1 := Item1;
        CardData2 := Item2;

        if CardData1.Index > CardData2.Index then
            Result := 1
        else if CardData1.Index = CardData2.Index then
            Result := 0
        else
            Result := -1;

end;

compare是給TList使用的



牌堆取牌器(52張牌)

用在發牌, 發麻將, 都還不錯.

當然啦,除非要用, 不然在小弟的強大墮性的驅使下, 不會花時間做任何的多型!

2010年1月15日 星期五

CuListCtrl - Encapsulates the functionality of a "list view control"

// Encapsulates the functionality of a "list view control"

m_ListCtrl.Create( WS_VISIBLE | WS_CHILD | LVS_REPORT | LVS_SHOWSELALWAYS , rt, hWnd, (UINT)&1);



// CuListCtrl.h

class CuListCtrl
{
private:
    CuWnd m_ListCtrlWnd;
public:
    CuListCtrl(void);
    ~CuListCtrl(void);

    virtual BOOL Create( DWORD dwStyle, const RECT& rect,
        HWND hParentWnd, UINT nID );

    int InsertColumn( int nCol, const LVCOLUMN* pColumn );
    int InsertColumn( int nCol, TCHAR * lpszColumnHeading, 
        int nFormat = LVCFMT_LEFT, int nWidth = -1,int nSubItem = -1 );

    int InsertItem( const LVITEM* pItem );
    int InsertItem( int nItem,  TCHAR * lpszItem );
    int InsertItem( int nItem,  TCHAR * lpszItem, int nImage );
    int InsertItem( UINT nMask, int nItem, TCHAR * lpszItem, 
        UINT nState, UINT nStateMask, int nImage, LPARAM lParam );

    BOOL SetItemText( int nItem, int nSubItem, TCHAR * lpszText );

};



// CuListCtrl.cpp

CuListCtrl::CuListCtrl(void)
{
}

CuListCtrl::~CuListCtrl(void)
{
}

BOOL CuListCtrl::Create(
                    DWORD dwStyle,
                    const RECT& rect,
                    HWND hParentWnd,
                    UINT nID 
                    )
{
    return m_ListCtrlWnd.Create(WC_LISTVIEW , L"", dwStyle, rect, hParentWnd, nID);
}

int CuListCtrl::InsertColumn( int nCol, const LVCOLUMN* pColumn )
{
    return ListView_InsertColumn(m_ListCtrlWnd.GetSafeHwnd() , nCol, pColumn) ;
}

int CuListCtrl::InsertColumn( int nCol, TCHAR *lpszColumnHeading, 
                 int nFormat /* = LVCFMT_LEFT */, int nWidth /* = -1 */ ,int nSubItem /* = -1 */)
{
    LV_COLUMN lvC = {0};
    lvC.mask = LVCF_FMT | LVCF_TEXT ;

    if( nWidth != -1 )
    {
        lvC.mask = lvC.mask | LVCF_WIDTH;
        lvC.cx = nWidth;
    }

    if( nSubItem != -1 )
    {
        lvC.mask = lvC.mask | LVCF_SUBITEM;
        lvC.iSubItem = nSubItem;
    }

    lvC.fmt = nFormat;
    lvC.pszText = lpszColumnHeading;

    return this->InsertColumn( nCol, &lvC);

}

int CuListCtrl::InsertItem( const LVITEM* pItem )
{
    return  ListView_InsertItem(m_ListCtrlWnd.GetSafeHwnd(), pItem);
}

int CuListCtrl::InsertItem( int nItem,  TCHAR * lpszItem )
{

    LVITEM lvI = {0};
    lvI.mask = LVIF_TEXT ;
    lvI.iItem = nItem;
    lvI.pszText = lpszItem;

    return this->InsertItem( &lvI);

}

int CuListCtrl::InsertItem( int nItem,  TCHAR * lpszItem, int nImage )
{
    LVITEM lvI = {0};
    lvI.mask = LVIF_TEXT | LVIF_IMAGE ;
    lvI.iItem = nItem;
    lvI.pszText = lpszItem;
    lvI.iImage = nImage;

    return this->InsertItem( &lvI);
}

int CuListCtrl::InsertItem( UINT nMask, int nItem, TCHAR * lpszItem, 
                           UINT nState, UINT nStateMask, int nImage, LPARAM lParam )
{

    LVITEM lvI = {0};
    lvI.mask = nMask;
    lvI.iItem = nItem;
    lvI.pszText = lpszItem;
    lvI.state = nState;
    lvI.stateMask = nStateMask;
    lvI.iImage = nImage;
    lvI.lParam = lParam;

    return this->InsertItem( &lvI);

}

BOOL CuListCtrl::SetItemText( int nItem, int nSubItem, TCHAR * lpszText )
{
    ListView_SetItemText( m_ListCtrlWnd.GetSafeHwnd(), nItem, nSubItem, lpszText)
    return true;
}

這個是很無聊的封裝, 但在CE上作業時, 不開MFC下, 也只能包一包

2010年1月14日 星期四

CuDebugger - Display PHP value about Array , Class detail information.

// Display PHP value about Array , Class detail information.

$debug = new CuDebugger
$debug->debug($result,  $key);


// CuDebugger.php

class CuDebugger  {

    var $m_Data;
    var $m_DataIndex;

    function CuDebugger() {
        $this->m_Data = array();
        $this->m_DataIndex = 0;
    }
    
    function debug($data, $key = null, $innerText = false)
    {
    
        $index = $this->m_DataIndex + 1;
        $this->m_Data[$index . " " .$key] = $data;
        $this->m_DataIndex = $index;
    }
    
    function innerText($data, $key = null)
    {
        $data = str_replace("<", "& lt;", $data);
        $data = str_replace(">", "& gt;", $data); 
        
        $this->debug($data, $key);
    }
    
    function GetHTML(){
        return $this->printArray($this->m_Data);
    }
    
    function printArray($var) {
        
        $title_string = "";
        $string_row = "";
        $string_value = "";
        $string = "";
        
        foreach($var as $key => $value){
            
            
            if( is_array($value) ) {
                $string_value .= $this->printArray($value, false);
            }
            elseif(gettype($value) == 'object') {
                $string_value .= "Object of class " . get_class($value) . " { ".serialize($value) . " } ";
            }
            elseif( $value ) {
                $string_value .= "$value";
            }
            else {
                $string_value .= "< BR >";
            }
            
            $string_row .= "<tr>\n<td><b>$key</b></td><td>$string_value</td></tr>\n";       
            $string_value = "";
            
        }
        
        if( $string_row ) {
            $string = '<table border = "1">'.$string_row;
            $string .= "</table>\n";
        }
        
        return $string;
        
        
    }   
}

2010年1月13日 星期三

CuEdit - provides the functionality of a Windows edit control.

// provides the functionality of a Windows edit control.


CuEdit gEdit;
gEdit.Create( WS_VISIBLE|WS_CHILD| WS_BORDER,
       CuRect(0, 0, 40 * 2 , 14 * 2), hWnd, (UINT)1);

gEdit.SetWindowText(TEXT("HI Edit"));

String strText;
gEdit.GetWindowText(strText);



// CuEdit.h


class CuEdit
{
    CuWnd m_EditWnd;
public:
    CuEdit(void);
    ~CuEdit(void);

    virtual BOOL Create( DWORD dwStyle, const RECT& rect, 
        HWND hParentWnd, UINT nID );

    void SetWindowText( LPCTSTR lpszString );
    void GetWindowText( String& rString ) const;
};




// CuEdit.cpp


CuEdit::CuEdit(void)
{
}

CuEdit::~CuEdit(void)
{
}

BOOL CuEdit::Create( DWORD dwStyle, const RECT& rect, 
                    HWND hParentWnd, UINT nID )
{
    return m_EditWnd.CreateEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), 
        TEXT(""), dwStyle, rect, hParentWnd, nID);
}


void CuEdit::SetWindowText( LPCTSTR lpszString )
{
    ::SetWindowText( m_EditWnd.GetSafeHwnd(), lpszString );
}

void CuEdit::GetWindowText( String& rString ) const
{
    int nLenght = ::GetWindowTextLength( m_EditWnd );
    TCHAR *pszBuffer = new TCHAR[nLenght + 1];

    ::GetWindowText(m_EditWnd , pszBuffer, nLenght);

    rString = pszBuffer;
    delete [] pszBuffer;
}
沒打算繼承CuWnd! 看不到多型 繼承後也沒任何好處!

2010年1月12日 星期二

CuWnd - is distinct from a Windows window

// is distinct from a Windows window

//
class CuMainWnd : public CuWnd {};

//
CuWnd ListCtrlWnd;
ListCtrlWnd.Create(WC_LISTVIEW , TEXT(""), dwStyle, rect, hParentWnd, nID);

CuWnd EditWnd;
EditWnd.CreateEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""), dwStyle, rect, hParentWnd, nID);
// CuWnd.h

class CuWnd
{
private:
    HWND m_hWnd;

private:

    //////////////////////////////////////////////////////////////////////
    // 函式名稱: WndProc
    // 函式說明: Create時預設的訊息回圈 會將訊息派送到 OnMsg裡
    //////////////////////////////////////////////////////////////////////
    static LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);

public:
    // 建構 解構
    CuWnd(void);
    virtual ~CuWnd(void);

protected:

    //////////////////////////////////////////////////////////////////////
    // 函式名稱: OnMsg
    // 函式說明: 繼承這個函式處理windows訊息
    //////////////////////////////////////////////////////////////////////
    virtual LRESULT OnMsg(MSG &msg);

public:

    virtual BOOL Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
        DWORD dwStyle,  const CuRect &rect, 
        HWND hParentWnd = NULL, UINT nID = NULL );

    virtual BOOL CreateEx( DWORD dwExStyle, LPCTSTR lpszClassName,
        LPCTSTR lpszWindowName, DWORD dwStyle, const CuRect& rect,
        HWND hParentWnd = NULL, UINT nID = NULL);

    ATOM WndRegisterClassEx(LPCTSTR szWindowClass);


    // inline 函式 實作碼在下方
    HWND GetSafeHwnd( ) const;
    BOOL ShowWindow(int nCmdShow);
    BOOL UpdateWindow();
    BOOL DestroyWindow();

    operator HWND() const
    {
        return GetSafeHwnd();
    }

public:
    // 訊息處理函式
    void OnDestroy();

};

inline HWND CuWnd::GetSafeHwnd() const
{ return (HWND)(this == NULL ? NULL : m_hWnd) ;}

inline BOOL CuWnd::ShowWindow(int nCmdShow)
{ return ::ShowWindow( m_hWnd, nCmdShow); }

inline BOOL CuWnd::UpdateWindow()
{ return ::UpdateWindow(m_hWnd); }

inline BOOL CuWnd::DestroyWindow()
{ 
 BOOL bResult = ::DestroyWindow(m_hWnd); 
 m_hWnd = NULL;
 return bResult;
}



// CuWnd.cpp


CuWnd::CuWnd(void)
:m_hWnd(NULL)
{

}

CuWnd::~CuWnd(void)
{
    this->DestroyWindow();
}


//////////////////////////////////////////////////////////////////////
// 函式名稱: OnMsg
// 函式說明: 預設訊息處理
//////////////////////////////////////////////////////////////////////
LRESULT CuWnd::OnMsg(MSG &msg)
{
    return 0;
}

void CuWnd::OnDestroy()
{
    PostQuitMessage(0);
}

LRESULT CALLBACK CuWnd::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static MSG msg;

    msg.hwnd = hWnd;
    msg.message = message;
    msg.wParam = wParam;
    msg.lParam = lParam;

    static CuWnd *pWnd = NULL;
    if( message == WM_CREATE )
    {
    
        CREATESTRUCT *pct = (LPCREATESTRUCT)lParam;
        ::SetWindowLong( hWnd , GWL_USERDATA, (LONG)pct->lpCreateParams );
        
    }


    pWnd = (CuWnd *)::GetWindowLong(hWnd, GWL_USERDATA);
    if( pWnd && pWnd->OnMsg(msg) )
        return 0;
    else
        return ::DefWindowProc(hWnd, message, wParam, lParam);
    


}

BOOL CuWnd::Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                    DWORD dwStyle, const CuRect &rect,
                    HWND hParentWnd /* = NULL */, UINT nID /* = NULL*/ )
{


    m_hWnd = ::CreateWindow(lpszClassName, lpszWindowName, dwStyle,
        rect.left, rect.top, rect.Width(), rect.Height(), 
        hParentWnd, (HMENU)nID, GetModuleHandle(NULL), (LPVOID) this);

    Assert( m_hWnd != NULL, L"CreateWindow Error");
    DWORD dwError = GetLastError();

    return (BOOL) (m_hWnd == NULL ? NULL : m_hWnd);

}

BOOL CuWnd::CreateEx( DWORD dwExStyle, LPCTSTR lpszClassName,
                      LPCTSTR lpszWindowName, DWORD dwStyle, const CuRect& rect,
                      HWND hParentWnd  /* = NULL */, UINT nID /* = NULL*/)
{

    m_hWnd = ::CreateWindowEx( dwExStyle, lpszClassName, 
        lpszWindowName, dwStyle, 
        rect.left, rect.top, rect.Width(), rect.Height(),
        hParentWnd, (HMENU)nID, GetModuleHandle(NULL), (LPVOID) this);

    Assert( m_hWnd != NULL, L"CreateWindow Error");
    DWORD dwError = GetLastError();

    return (BOOL) (m_hWnd == NULL ? NULL : m_hWnd);
}


ATOM CuWnd::WndRegisterClassEx(LPCTSTR szWindowClass)
{

    WNDCLASS    wc;
    
    wc.style            = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc      = (WNDPROC) WndProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = GetModuleHandle(NULL);
    wc.hIcon            = 0;
    wc.hCursor          = 0;
    wc.hbrBackground    = 0;
    wc.lpszMenuName     = 0;
    wc.lpszClassName    = szWindowClass;
    
    return RegisterClass(&wc);


}

2010年1月11日 星期一

CCriticalSection - a critical section object.

// a critical section object.

CCriticalSection m_cs;
...


m_cs.Enter();
...
m_cs.Leave();

// CCriticalSection.h


class CCriticalSection  
{
    CRITICAL_SECTION m_CriticalSection;
public:
    void Leave();
    void Enter();

    CCriticalSection();
    virtual ~CCriticalSection();

};




// CCriticalSection.cpp

CCriticalSection::CCriticalSection()
{
    ::InitializeCriticalSection(&m_CriticalSection);
}

CCriticalSection::~CCriticalSection()
{
    ::DeleteCriticalSection(&m_CriticalSection);
}

void CCriticalSection::Enter()
{
    ::EnterCriticalSection(&m_CriticalSection);
}

void CCriticalSection::Leave()
{
    ::LeaveCriticalSection(&m_CriticalSection);
}


2010年1月10日 星期日

CuKeyStatusComposite - group of KeyStatus

// group of KeyStatus


CuKeyStatusComposite ksComposite;

for( int j = 0 ; j < arr.size() ; j++ )
{
    CuKeyStatus *pks = new CuKeyStatus;
    // ...
    ksComposite.push_back(pks);
}

ksComposite.clear();

// CuKeyStatusComposite.h

class CuKeyStatusComposite :
 public TuComposite<CuKeyStatus>
{
public:
    CuKeyStatusComposite(void);
    ~CuKeyStatusComposite(void);

    int GetEqualItemIndex( CuKeyStatus &KeyStatus);
};



// CuKeyStatusComposite.cpp

CuKeyStatusComposite::CuKeyStatusComposite(void)
{
}

CuKeyStatusComposite::~CuKeyStatusComposite(void)
{
    this->clear();
}

int CuKeyStatusComposite::GetEqualItemIndex( CuKeyStatus &KeyStatus)
{
    int nResult = -1;
    
    _itor = _itsElement.begin();
    
    while(  _itor != _itsElement.end() )
    {
    
        if( KeyStatus == *(*_itor) )
        {
            nResult = _itor - _itsElement.begin();
            break;
        }
    
        _itor++;
    
    }
    
    return nResult;

}
GetEqualItemIndex 只有這個專案需要, 沒有打算移到 TuComposite 內, 下次在遇到時, 在處理.

2010年1月9日 星期六

CReg - An encapsulation of the Windows registry key.

// An encapsulation of the Windows registry key.  


CReg reg(HKEY_LOCAL_MACHINE, TEXT("Software\\AppName\\"));
string strPath = reg.ValueSZ( "KeyName" );


// CReg.h

class CReg  
{
private:
    HKEY    m_hKey;
    int     m_Index;
    LPBYTE  m_lpbValue; // last value read, if any

public:
    CReg();
    ~CReg();

    BOOL Create(HKEY hkRoot, LPCTSTR pszKey) {
        DWORD dwDisp;
        return ERROR_SUCCESS==RegCreateKeyEx(hkRoot, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hKey, &dwDisp);
    }

    BOOL Open(HKEY hkRoot, LPCTSTR pszKey, REGSAM sam=KEY_READ) {
        return ERROR_SUCCESS==RegOpenKeyEx(hkRoot, pszKey, 0, sam, &m_hKey);
    }

    CReg(HKEY hkRoot, LPCTSTR pszKey) {
        m_hKey = NULL;
        m_Index = 0;
        m_lpbValue = NULL;
        Open(hkRoot, pszKey);
    }



    void MyFree(LPBYTE m_lpbValue) {
        delete [] m_lpbValue;
    }

    LPBYTE MyRgAlloc(int dwLen)
    {
        return new BYTE[dwLen];
    }

    void Reset() { 
        if(m_hKey) RegCloseKey(m_hKey); 
        MyFree(m_lpbValue);
        m_hKey = NULL;
        m_Index = 0;
        m_lpbValue = NULL;
    }

    operator HKEY() { return m_hKey; }

    BOOL IsOK(void) { return m_hKey!=NULL; }


    BOOL EnumKey(LPTSTR psz, DWORD dwLen) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegEnumKeyEx(m_hKey, m_Index++, psz, &dwLen, NULL, NULL, NULL, NULL);
    }

    BOOL EnumValue(LPTSTR pszName, DWORD dwLenName, LPTSTR pszValue, DWORD dwLenValue) {
        DWORD dwType;
        if(!m_hKey) return FALSE;
        dwLenValue *= sizeof(TCHAR); // convert length in chars to bytes
        return ERROR_SUCCESS==RegEnumValue(m_hKey, m_Index++, pszName, &dwLenName, NULL, &dwType, (LPBYTE)pszValue, &dwLenValue);
    }

    BOOL ValueSZ(LPCTSTR szName, LPTSTR szValue, DWORD dwLen) 
    {
        if(!m_hKey) return FALSE;
        dwLen *= sizeof(TCHAR); // convert length in chars to bytes
        return ERROR_SUCCESS==RegQueryValueEx(m_hKey, szName, NULL, NULL, (LPBYTE)szValue, &dwLen);
    }

    DWORD ValueBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen) {
        if(!m_hKey) return FALSE;
        DWORD dwLenWant = dwLen;
        if(ERROR_SUCCESS==RegQueryValueEx(m_hKey, szName, NULL, NULL, lpbValue, &dwLen))
            return dwLen;
        else
            return 0;
    }

    LPCTSTR ValueSZ(LPCTSTR szName)
    {
        if(!m_hKey) return TEXT("");
        DWORD dwLen = 0;
        if( (ERROR_SUCCESS != RegQueryValueEx(m_hKey, szName, NULL, NULL, NULL, &dwLen)) || 
            (dwLen == 0) )
                return TEXT("");
        MyFree(m_lpbValue);
        if( !(m_lpbValue = MyRgAlloc(dwLen)) ||
            (ERROR_SUCCESS != RegQueryValueEx(m_hKey, szName, NULL, NULL, m_lpbValue, &dwLen)) )
                return TEXT("");
        return (LPTSTR)m_lpbValue;
    }

    LPBYTE ValueBinary(LPCTSTR szName) {
        return (LPBYTE)ValueSZ(szName);
    }

    DWORD ValueDW(LPCTSTR szName, DWORD dwDefault=0) {
        if(!m_hKey) return FALSE;
        DWORD dwValue = dwDefault;
        DWORD dwLen = sizeof(DWORD);
        RegQueryValueEx(m_hKey, szName, NULL, NULL, (LPBYTE)&dwValue, &dwLen);
        return dwValue;
    }

    LONG  ValueDW2(LPCTSTR szName, DWORD &dwDefault) {
        if(!m_hKey) return FALSE;
        DWORD dwValue = dwDefault;
        DWORD dwLen = sizeof(DWORD);
        return RegQueryValueEx(m_hKey, szName, NULL, NULL, (LPBYTE)&dwValue, &dwLen);
    }

    BOOL SetSZ(LPCTSTR szName, LPCTSTR szValue, DWORD dwLen) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_SZ, (LPBYTE)szValue, sizeof(TCHAR)*dwLen);
    }
    
    BOOL SetSZ(LPCTSTR szName, LPCTSTR szValue) {
        return SetSZ(szName, szValue, 1+lstrlen(szValue));
    }

    BOOL SetDW(LPCTSTR szName, DWORD dwValue) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
    }
    
    BOOL SetBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_BINARY, lpbValue, dwLen);
    }

    BOOL SetMultiSZ(LPCTSTR szName, LPCTSTR lpszValue, DWORD dwLen) {
        return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_MULTI_SZ, (LPBYTE)lpszValue, sizeof(TCHAR)*dwLen);
    }

    BOOL DeleteValue(LPCTSTR szName) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegDeleteValue(m_hKey, szName);
    }

    BOOL DeleteKey(LPCTSTR szName) {
        if(!m_hKey) return FALSE;
        return ERROR_SUCCESS==RegDeleteKey(m_hKey, szName);
    }
};


// CReg.cpp

CReg::CReg()
{
        m_hKey = NULL;
        m_Index = 0;
        m_lpbValue = NULL;
}

CReg::~CReg()
{
    if(m_hKey) 
        RegCloseKey(m_hKey); 
    MyFree(m_lpbValue);
}

2010年1月8日 星期五

CuRecord - Access Record

// Access Record

$record = new CuRecord($ado, $table_name, $key);

//
$record->SetField("field_name", $field_value );
$record->Save();

//
$record->Load("field_name", $field_value);
$value = $record->GetField("field_name");

//
$record->Load("field_name", $field_value);
$record->Destroy();


// CuRecord.php

class CuRecord  {

    var $ado;
    var $table_name; 
    
    var $key_name; 
    var $key_value; 
    
    var $database_fields;
    var $modified_fields;
    
    
    function CuRecord($ado, $table_name, $key_name = "sn" , $key_value = "") {
        
        $this->ado = &$ado;
        $this->table_name = $table_name;
        $this->key_name = $key_name;
        $this->key_value = $this->_check_input($key_value);
        
        $this->database_fields = array();
        $this->modified_fields = array();        
    }
    
    
    function SetField( $field, $value) {

        if( is_numeric($field) ) 
            return;
        
        $this->database_fields[$field] = $value;
        $this->modified_fields[$field] = true;

    }


    function GetField($field) {
        return $this->database_fields[$field]; 
    }   


    function Destroy() {
        
        if( !$this->key_value )
            return;
        return $this->ado->sql("DELETE FROM $this->table_name WHERE $this->key_name = '$this->key_value'");
        
    }   
    

    function Save()
    {
        
        if( $this->key_value )
        {
            $result = $this->_update();
        }
        else
        {
            $result = $this->_insert();
            $this->_load_key_value();
        }
        
        return $this->key_value;
    }
    

    function Load($bargain_field, $bargain_value)
    {
        
        if(!($bargain_field && $bargain_value ))
        {
            $bargain_field = $this->key_name;
            $bargain_value = $this->key_value;
        }
        
        if( !($bargain_field && $bargain_value ) )
            return;
        
        $value = $this->_check_input($bargain_value);
        $stmt = "`$bargain_field` = '$value'";
        $stmt = "SELECT * FROM $this->table_name WHERE $stmt";
         
        $result = $this->ado->sql($stmt);
        if( $result == "" )
            return ;
        
        $result_table = $this->ado->fetch_array();
        $this->database_fields = $result_table[0];
        
        if( sizeof($this->modified_fields) > 0 ) {
            foreach( $this->modified_fields as $key => $value ) {
                $this->modified_fields[$key] = false;
            }
        }       
        
        $this->key_value = $result_table[0][$this->key_name];
        
        return $this->key_value;
        
    }
    

    function _load_key_value()
    {
        $stmt = "SELECT MAX($this->key_name) AS $this->key_name FROM `$this->table_name` WHERE ";
        foreach( $this->database_fields as $key => $value ){
            if( !is_numeric($key) && $value ){
                if( $this->modified_fields[$key] == true ){
                    $value = $this->_check_input($value); 
                    $stmt .= "`$key` = '$value' AND ";
                }
            }
        } 
        
        $stmt = substr($stmt,0,strlen($stmt)-5);    
        $handle = $this->ado->sql($stmt);
        
        $result_table = $this->ado->fetch_array();
        $this->key_value = $result_table[0][$this->key_name];
        
        return $result_rows;
    }
    

    function _insert() {

        $stmt = "INSERT INTO `$this->table_name` ";
        
        foreach ($this->database_fields as $key => $value) {
            if( !is_numeric( $key )&& $value){
                $key = $this->_check_input($key);
                $key_stmt .= " `$key`,";
                
                $value = $this->_check_input($value);
                $value_stmt .= " '$value',";
                
            }
        }
        
        $key_stmt = substr($key_stmt,0,strlen($key_stmt)-1); 
        $value_stmt = substr($value_stmt,0,strlen($value_stmt)-1); 
        
        $stmt .= " (" . $key_stmt . ") VALUES (" . $value_stmt . ")" ;
        $handle = $this->ado->sql($stmt, "_insert");
        
        
        return $handle . " " . $stmt;
        
    }    
    
    
    function _update() {
        
        $field_value = $this->key_value;
        $field_name = $this->key_name;
        $table_name = $this->table_name;
        
        $stmt = "UPDATE `$table_name` SET ";
        foreach ($this->database_fields as $key => $value) {
            if( !is_numeric( $key ) ){
                if( $this->modified_fields[$key] == true ) {
                    $value = $this->_check_input($value);
                    if( $value == "" ){
                        $stmt .= "`$key` = 'NULL', ";
                    }
                    else {
                        $stmt .= "`$key` = '$value', ";
                    }
                }
            }
        }
        
        $stmt = substr($stmt, 0, strlen($stmt) - 2);
        $stmt .= " WHERE `$field_name` = '$field_value'"; 
        
        $handle = $this->ado->sql($stmt);
        return $handle . " " . $stmt;
        
    } 
    
    
    function _check_input($value)
    {
        if($value == "")
            return "";

        if (get_magic_quotes_gpc())
        {
            $value = stripslashes($value);
        }
        
        if (!is_numeric($value))
        {
            $value =  mysql_real_escape_string($value);
        }
        
        return $value;
    }
}

2010年1月7日 星期四

CuSize - Similar to the Windows SIZE structure

// Similar to the Windows SIZE structure

// CuSize.h

class CuSize : public tagSIZE
{
public:

// Constructors
    // construct an uninitialized size
    CuSize() throw();
    // create from two integers
    CuSize(int initCX, int initCY) throw();
    // create from another size
    CuSize(SIZE initSize) throw();
    // create from a point
    CuSize(POINT initPt) throw();
    // create from a DWORD: cx = LOWORD(dw) cy = HIWORD(dw)
    CuSize(DWORD dwSize) throw();

// Operations
    BOOL operator==(SIZE size) const throw();
    BOOL operator!=(SIZE size) const throw();
    void operator+=(SIZE size) throw();
    void operator-=(SIZE size) throw();
    void SetSize(int CX, int CY) throw();

// Operators returning CuSize values
    CuSize operator+(SIZE size) const throw();
    CuSize operator-(SIZE size) const throw();
    CuSize operator-() const throw();

// Operators returning CuPoint values
    CuPoint operator+(POINT point) const throw();
    CuPoint operator-(POINT point) const throw();

// Operators returning CuRect values
    CuRect operator+(const RECT* lpRect) const throw();
    CuRect operator-(const RECT* lpRect) const throw();
};

inline CuSize::CuSize()
    { /* random filled */ }
inline CuSize::CuSize(int initCX, int initCY)
    { cx = initCX; cy = initCY; }
inline CuSize::CuSize(SIZE initSize)
    { *(SIZE*)this = initSize; }
inline CuSize::CuSize(POINT initPt)
    { *(POINT*)this = initPt; }
inline CuSize::CuSize(DWORD dwSize)
    {
        cx = (short)LOWORD(dwSize);
        cy = (short)HIWORD(dwSize);
    }
inline BOOL CuSize::operator==(SIZE size) const
    { return (cx == size.cx && cy == size.cy); }
inline BOOL CuSize::operator!=(SIZE size) const
    { return (cx != size.cx || cy != size.cy); }
inline void CuSize::operator+=(SIZE size)
    { cx += size.cx; cy += size.cy; }
inline void CuSize::operator-=(SIZE size)
    { cx -= size.cx; cy -= size.cy; }
inline void CuSize::SetSize(int CX, int CY)
    { cx = CX; cy = CY; }   
inline CuSize CuSize::operator+(SIZE size) const
    { return CuSize(cx + size.cx, cy + size.cy); }
inline CuSize CuSize::operator-(SIZE size) const
    { return CuSize(cx - size.cx, cy - size.cy); }
inline CuSize CuSize::operator-() const
    { return CuSize(-cx, -cy); }
inline CuPoint CuSize::operator+(POINT point) const
    { return CuPoint(cx + point.x, cy + point.y); }
inline CuPoint CuSize::operator-(POINT point) const
    { return CuPoint(cx - point.x, cy - point.y); }
inline CuRect CuSize::operator+(const RECT* lpRect) const
    { return CuRect(lpRect) + *this; }
inline CuRect CuSize::operator-(const RECT* lpRect) const
    { return CuRect(lpRect) - *this; }

2010年1月6日 星期三

CuADO - connection to a MySQL Server

// connection to a MySQL Server

$this->ado = new CuADO;
$ado->Connect($host, $username, $password);
$ado->SelectDB($db); 


// CuADO.php


class CuADO  {
    
    var $link;
    var $query_handle;
    
    function CuADO() {
        
    }
    
    function Connect($host, $username, $password)
    {
        $this->link = mysql_connect($host, $username, $password);
        return $this->link;
    }
    
    function SelectDB($db)
    {
        return mysql_select_db($db, $this->link);
    }

    function sql($stmt, $debug_key = "")
    {
        $this->query_handle = mysql_query($stmt, $this->link) ;
        return $this->query_handle;
    }

    function fetch_array() {
        
        $query_handle = &$this->query_handle;
        $i = 0;
        while($result_rows[$i] = mysql_fetch_array( $query_handle ) ){
            $i++;
        }
        
        return $result_rows;
        
    }   
    
}


2010年1月5日 星期二

TuComposite - Template of Composite pattern

// allows a group of objects to be treated in the same way as a single instance of an object.

//
TuComposite<CuMyObject> myComposite;
CuMyObject *pMyObject = &myComposite;

//
class CuMyCompositeObject : public TuComposite<CuMyObject> 
{
    ...
};

// TuComposite.h


template <typename T>
class TuComposite : public T
{
protected:
    vector<T*> _itsElement;
    typename vector<T*>::iterator _itor; 
    
public:

    TuComposite(){};
    virtual ~TuComposite(){};

    void push_back(T *pElement){ _itsElement.push_back(pElement); }
    void insert(int n, T *pElement){ _itsElement.insert(_itsElement.begin() + n, pElement); }

    T* at(const int nIndex){ return _itsElement[nIndex]; }
    void reserve( int _Count ){_itsElement.reserve(_Count); }

    int size(){ return _itsElement.size(); }
    
    void remove(T *pElement);
    void clear();
    
    
};

template <typename T>
void TuComposite<T>::clear()
{
    
    _itor = _itsElement.begin();
    
    while(  _itor != _itsElement.end() )
    {
        
        T* pElement = *_itor;
        delete pElement;
        _itor++;
        
    }
    
    _itsElement.clear();
    
}

template <typename T>
void TuComposite<T>::remove(T *pElement)
{
    
    _itor = _itsElement.begin();
    
    while(  _itor != _itsElement.end() )
    {
        
        if( pElement == *_itor )
        {
            _itsElement.erase(_itor);
            break;
        }
        _itor++;
        
    }
    
}

TuList - General purpose container of a list of objects

// General purpose container of a list of objects

ObjList : TuList;
ObjList := TuList.Create();
ObjList.Add(MyObject);

MyObject := ObjList.GetItems(i);
ObjList.Free;

// u_TList.pas

unit u_TList;

interface
uses
      Windows, Classes, SysUtils,
      StdCtrls,
      ch_LogMessages;

type

      TuList = class
        private
          m_List : TList;
        public
          constructor Create();
          destructor Destroy();  override;
          procedure Clear();
          function Count: Integer;
          function Add( Item:Pointer ):Integer;
          function GetItems(Index: Integer): Pointer;
          procedure Sort(Compare: TListSortCompare);
          procedure Delete(Index: Integer);
      end;

implementation

{ TuList }


function TuList.Add(Item: Pointer): Integer;
begin
        Result := m_List.Add(Item);
end;

procedure TuList.Clear;
begin
        m_List.Clear;
end;

function TuList.Count: Integer;
begin
        Result := m_List.Count;
end;

constructor TuList.Create;
begin
        m_List := TList.Create;
end;

procedure TuList.Delete(Index: Integer);
begin
        m_List.Delete(Index);
end;

destructor TuList.Destroy;
begin
        m_List.Free;
        inherited;
end;

function TuList.GetItems(Index: Integer): Pointer;
begin

        if (Index < 0) or (Index >= m_List.Count ) then begin
            Index := 0;
        end;

        Result := m_List.Items[Index];

end;


procedure TuList.Sort(Compare: TListSortCompare);
begin
        m_List.Sort(Compare);
end;

end.

2010年1月4日 星期一

CuKeyStatus - a struct of the keyboard status.

// a struct of the keyboard status. 
// override operator == 
CuKeyStatus ksFromLLKeyHook;
CuKeyStatus ksClientDefault;

Assert( ksFromLLKeyHook == ksClientDefault );

// CuKeyStatus.h
class CuKeyStatus
{
public:
    BOOL m_bAlt;
    BOOL m_bCtrl;
    BOOL m_bShift;
    DWORD m_dwScanCode;
    DWORD m_dwVirtualKey;

    CuKeyStatus()
        :m_bAlt(FALSE)
        ,m_bCtrl(FALSE)
        ,m_bShift(FALSE)
        ,m_dwScanCode(0)
        ,m_dwVirtualKey(0)
    {};
    ~CuKeyStatus(void){};

    BOOL operator == (CuKeyStatus &KeyStatus);
    
};

inline BOOL CuKeyStatus::operator == (CuKeyStatus &KeyStatus)
{
    return m_bAlt == KeyStatus.m_bAlt &&
        m_bCtrl == KeyStatus.m_bCtrl &&
        m_bShift == KeyStatus.m_bShift &&
        m_dwScanCode == KeyStatus.m_dwScanCode &&
        m_dwVirtualKey == KeyStatus.m_dwVirtualKey ;
}

2010年1月3日 星期日

CuMenu - An encapsulation of the Windows HMENU.

// An encapsulation of the Windows HMENU. 

CuMenu MenuTray.LoadMenu(IDR_MENU_MYMENU);
CuMenu *pTrackMenu = MenuTray.GetSubMenu(0);
pTrackMenu->TrackPopupMenu(TPM_BOTTOMALIGN, pt.x, pt.y, this->GetSafeHwnd() );  
MenuTray.DestroyMenu();



// CuMenu.h

class CuMenu
{
    HMENU m_hMenu;
public:
    CuMenu(void);
    ~CuMenu(void);

    BOOL DestroyMenu();
    BOOL LoadMenu( UINT nIDResource );
    CuMenu* GetSubMenu( int nPos ) const;

    BOOL Attach( HMENU hMenu );
    BOOL TrackPopupMenu(
        UINT nFlags,
        int x,
        int y,
        HWND hWnd,
        LPCRECT lpRect = 0
        );

};



// CuMenu.cpp


CuMenu::CuMenu(void)
:m_hMenu(NULL)
{
}

CuMenu::~CuMenu(void)
{
    DestroyMenu();
}

BOOL CuMenu::LoadMenu( UINT nIDResource )
{
    m_hMenu = ::LoadMenu(::GetModuleHandle(NULL), MAKEINTRESOURCE(nIDResource));
    return ( m_hMenu != NULL );
}

CuMenu* CuMenu::GetSubMenu( int nPos ) const
{
    HMENU hMenu = ::GetSubMenu( m_hMenu, nPos );

    static CuMenu SubMenu;
    SubMenu.Attach(hMenu);
    return &SubMenu;
}

BOOL CuMenu::Attach( HMENU hMenu )
{
    m_hMenu = hMenu;
    return ( m_hMenu != NULL );
}

BOOL CuMenu::TrackPopupMenu(
                    UINT nFlags,
                    int x,
                    int y,
                    HWND hWnd,
                    LPCRECT lpRect /*= 0*/
                    )
{
    return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect);
}

BOOL CuMenu::DestroyMenu()
{
    return ::DestroyMenu(m_hMenu);
}


2010年1月2日 星期六

CuKeyboard - Conversion LowLevelKeyHook to CuKeyStatus

// Conversion LowLevelKeyHook to CuKeyStatus


LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{

    static CuKeyboard Keyboard;
    Keyboard.FromLowLevelKeyHook(wParam, lParam);
    
    CuKeyNameTextEx KeyNameTextEx(Keyboard.GetKeyStatus());
    
    wstring strKeyboard = KeyNameTextEx;
 
    return 0;
}

CuHook hook;
hook.Init(HookProc, WH_KEYBOARD_LL);


// CuKeyboard.h


class CuKeyboard
{
    CuKeyStatus m_KeyStatus;
    BOOL m_bScanCode[256];

public:
    CuKeyboard(void);
    ~CuKeyboard(void);

    void FromLowLevelKeyHook(WPARAM wParam, LPARAM lParam);
    CuKeyStatus GetKeyStatus(){ return m_KeyStatus; }
private:
    bool IsFunctionKey(DWORD dwScanCode);

};


// CuKeyboard.cpp


CuKeyboard::CuKeyboard(void)
{
    memset((void*)m_bScanCode, 0, sizeof(m_bScanCode)  );
}

CuKeyboard::~CuKeyboard(void)
{
}


void CuKeyboard::FromLowLevelKeyHook(WPARAM wParam, LPARAM lParam)
{
    KBDLLHOOKSTRUCT *pKB = (KBDLLHOOKSTRUCT *)lParam;

    //
    BOOL bKeyDown = ( (wParam == WM_KEYDOWN) || (wParam == WM_SYSKEYDOWN) );
    m_bScanCode[pKB->scanCode] = bKeyDown;


    // 
    if( IsFunctionKey(pKB->scanCode) )
    {
        m_KeyStatus.m_bAlt = m_bScanCode[56];
        m_KeyStatus.m_bCtrl = m_bScanCode[29];
        m_KeyStatus.m_bShift = (m_bScanCode[42] || m_bScanCode[54]);
    }
    else
    {
        if( !bKeyDown )
            m_KeyStatus.m_dwScanCode = 0;
        else
            m_KeyStatus.m_dwScanCode = pKB->scanCode; 
    }

}

bool CuKeyboard::IsFunctionKey(DWORD dwScanCode)
{
    return ((dwScanCode == 56) || (dwScanCode == 29) || (dwScanCode == 42) || (dwScanCode == 54));
}

2010年1月1日 星期五

CuPoint - A 2-D point, similar to Windows POINT structure.

// CuPoint - A 2-D point, similar to Windows POINT structure.

class CuPoint : public tagPOINT
{
public:
// Constructors

    // create an uninitialized point
    CuPoint() throw();
    // create from two integers
    CuPoint(int initX, int initY) throw();
    // create from another point
    CuPoint(POINT initPt) throw();
    // create from a size
    CuPoint(SIZE initSize) throw();
    // create from an LPARAM: x = LOWORD(dw) y = HIWORD(dw)
    CuPoint(LPARAM dwPoint) throw();


// Operations

// translate the point
    void Offset(int xOffset, int yOffset) throw();
    void Offset(POINT point) throw();
    void Offset(SIZE size) throw();
    void SetPoint(int X, int Y) throw();

    BOOL operator==(POINT point) const throw();
    BOOL operator!=(POINT point) const throw();
    void operator+=(SIZE size) throw();
    void operator-=(SIZE size) throw();
    void operator+=(POINT point) throw();
    void operator-=(POINT point) throw();

// Operators returning CuPoint values
    CuPoint operator+(SIZE size) const throw();
    CuPoint operator-(SIZE size) const throw();
    CuPoint operator-() const throw();
    CuPoint operator+(POINT point) const throw();

// Operators returning CuSize values
    CuSize operator-(POINT point) const throw();

// Operators returning CuRect values
    CuRect operator+(const RECT* lpRect) const throw();
    CuRect operator-(const RECT* lpRect) const throw();
};


inline CuPoint::CuPoint()
    { /* random filled */ }
inline CuPoint::CuPoint(int initX, int initY)
    { x = initX; y = initY; }
inline CuPoint::CuPoint(POINT initPt)
    { *(POINT*)this = initPt; }
inline CuPoint::CuPoint(SIZE initSize)
    { *(SIZE*)this = initSize; }
inline CuPoint::CuPoint(LPARAM dwPoint)
    {
        x = (short)LOWORD(dwPoint);
        y = (short)HIWORD(dwPoint);
    }
inline void CuPoint::Offset(int xOffset, int yOffset)
    { x += xOffset; y += yOffset; }
inline void CuPoint::Offset(POINT point)
    { x += point.x; y += point.y; }
inline void CuPoint::Offset(SIZE size)
    { x += size.cx; y += size.cy; }
inline void CuPoint::SetPoint(int X, int Y)
    { x = X; y = Y; }
inline BOOL CuPoint::operator==(POINT point) const
    { return (x == point.x && y == point.y); }
inline BOOL CuPoint::operator!=(POINT point) const
    { return (x != point.x || y != point.y); }
inline void CuPoint::operator+=(SIZE size)
    { x += size.cx; y += size.cy; }
inline void CuPoint::operator-=(SIZE size)
    { x -= size.cx; y -= size.cy; }
inline void CuPoint::operator+=(POINT point)
    { x += point.x; y += point.y; }
inline void CuPoint::operator-=(POINT point)
    { x -= point.x; y -= point.y; }
inline CuPoint CuPoint::operator+(SIZE size) const
    { return CuPoint(x + size.cx, y + size.cy); }
inline CuPoint CuPoint::operator-(SIZE size) const
    { return CuPoint(x - size.cx, y - size.cy); }
inline CuPoint CuPoint::operator-() const
    { return CuPoint(-x, -y); }
inline CuPoint CuPoint::operator+(POINT point) const
    { return CuPoint(x + point.x, y + point.y); }
inline CuSize CuPoint::operator-(POINT point) const
    { return CuSize(x - point.x, y - point.y); }
inline CuRect CuPoint::operator+(const RECT* lpRect) const
    { return CuRect(lpRect) + *this; }
inline CuRect CuPoint::operator-(const RECT* lpRect) const
    { return CuRect(lpRect) - *this; }

CuKeyNameTextEx - retrieves a string that represents the name of a composite key

// retrieves a string that represents the name of a composite key

CuKeyStatus KeyStatus;
....

CuKeyNameTextEx KeyNameTextEx(KeyStatus);
wstring strKeyText = KeyNameTextEx;
// Assert( strKeyText == TEXT("Alt+Ctrl+Shift+D"));
// Assert( strKeyText == TEXT("Alt+Ctrl+D"));
// Assert( strKeyText == TEXT("Ctrl+Shift+D"));


// CuKeyNameTextEx.h

class CuKeyNameTextEx
{
    wstring m_strKeyText;

public:
    CuKeyNameTextEx(void);
    CuKeyNameTextEx(CuKeyStatus &KeyStatus);
    ~CuKeyNameTextEx(void);

    void SetKeyStatus(CuKeyStatus &KeyStatus);
    
    operator wstring() const
    {
        return m_strKeyText;
    };
    BOOL IsMustAdd(bool l, bool r);
private:
    wstring ProcessFunctionKey(CuKeyStatus &KeyStatus);
};




// CuKeyNameTextEx.cpp

CuKeyNameTextEx::CuKeyNameTextEx(void)
{
}

CuKeyNameTextEx::~CuKeyNameTextEx(void)
{
}

CuKeyNameTextEx::CuKeyNameTextEx(CuKeyStatus &KeyStatus)
{
    SetKeyStatus(KeyStatus);
}


void CuKeyNameTextEx::SetKeyStatus(CuKeyStatus &KeyStatus)
{

    if( !KeyStatus.m_dwScanCode )
        return;

    wstring strResult;

    strResult = ProcessFunctionKey(KeyStatus);
    
    CuKeyNameText KeyName(KeyStatus.m_dwScanCode);
    wstring strKeyText = KeyName;

    wstring strAdd = TEXT("+");
    if( !strKeyText.empty() && !strResult.empty() )
        strResult += strAdd;
    
    strResult += strKeyText;

    m_strKeyText = strResult;

}


wstring CuKeyNameTextEx::ProcessFunctionKey(CuKeyStatus &KeyStatus)
{

    wstring strResult;

    wstring strAlt = TEXT("Alt");
    wstring strCtrl = TEXT("Ctrl");
    wstring strShift = TEXT("Shift");
    wstring strAdd = TEXT("+");


    if( KeyStatus.m_bAlt )
        strResult += strAlt;

    if( KeyStatus.m_bAlt && KeyStatus.m_bCtrl )
        strResult += strAdd;

    if( KeyStatus.m_bCtrl )
        strResult += strCtrl;

    if( KeyStatus.m_bShift && (KeyStatus.m_bAlt || KeyStatus.m_bCtrl) )
        strResult += strAdd;

    if( KeyStatus.m_bShift )
        strResult += strShift;

    return strResult;
}