2014年12月9日 星期二

簡單的 Makefile 說明

 GCC 下 makefile 的用法為在 command line 下執行

make -f <file> <rule>

如果不設定指定檔案, 默認執行 Makefile 這個檔案, 與 all 這個 rule.
* 在 windows MinGW 下記得將  MinGW 路徑加入環境變數, 不然會不認識 make
* 在 linux MinGW 使用 cross compiler 則用 mingw32-make -f <file> <rule>

Visual studio 下 必須先開啟 Visual studio Tools 底下的命令列模式( EX: Visual studio 2005 命令提示字元), 然後執行

NMAKE /f <file> <rule>

makefile 其他常見的 rule
make clean     清除編譯過程中所產生的文件
make distclean 清除編譯過程中所產生的文件,還有 configure 所產生的 Makefile
make install   安裝至系統
make dist      將原始碼壓縮成 *.tar.gz
make distcheck 將原始碼壓縮成 *.tar.gz 檔,並測試。 

簡易 Makefile 語法解釋如下
---------------------------------------------------------------------------------------------------------------------

# 以 # 開頭的即為註解。
 !include <ntwin32.mak>

 # 變數宣告不分大小寫
Target=Gilgamesh.exe
# 慣例上, 給外部使用的變數名稱使用大寫
OBJECTS = Gilgamesh.obj Gilgamesh.rbj
 # 利用 $(cflags)${cflags} 來存取已定義的變數
cflags = $(cflags) /openmp
# 慣例上,內部使用的變數名稱使用小寫
extdflags = -DVisualStudio -DNDEBUG -DWINDOWS
# Makefile會在展開後,再決定變數的值。
# := 表示變數的值決定於它在 Makefile 中的位置, 而不是展開後
dflags :=  $(extdflags) $(dflags)
# 取消該變數
LIB_DIR=
# ?= 若變數未定義,則替它指定新的值。否則,採用原有的值。
FOO ?= wtf
# 與C語法相同, 自身再加上數值
cflags += -O2
# rule 功用為指示如何進行編譯
all: $(Target)
# <target>:<dependencies>
# target要建立的檔案
# dependencies:相依項目。決定是否要重新編譯。
Gilgamesh.obj: Gilgamesh.c
# 建立檔案的指令, 前面必須是 Tab, 不能為空白, 所有 Tab 開頭會被視為 shell script / batch 指令
    $(cc) $(cflags) $(cvars) $(dflags) $(hflags) Gilgamesh.c

Gilgamesh.res: Gilgamesh.rc
    $(rc) -DWIN32 -DNDEBUG $(hflags) -r Gilgamesh.rc

Gilgamesh.rbj: Gilgamesh.res
    cvtres $(cvflags) -machine:ix86 -o Gilgamesh.rbj Gilgamesh.res

$(Target): $(OBJECTS)
    $(link) /libpath:$(LIB_DIR) /out:$(Target) $(OBJECTS)

clean:
# @:不要顯示執行的指令。
# \換行用
    @for %%x in (obj exp pdb ilk res rbj) do \
    if exist *.%%x del *.%%x
# -:指令出錯也不中斷執行。
    -for %%x in (exe dll lib) do if exist Gilgamesh.%%x del Gilgamesh.%%x

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

因為我很懶, 通常我會將命令先寫成 *.bat 或 *.sh

Windows MinGW32 範例 gcc.bat
 ---------------------------------------------------------------------------------------------------------------------
@ECHO off

SET GCCBIN=c:\MinGW\bin
SET GCCMAKE=C:\MinGW\msys\1.0\bin
SET path=%GCCBIN%;%GCCMAKE%;%path%

IF EXIST %GCCBIN%\gcc.exe (
GOTO HELL
)

ECHO can not find MinGW
PAUSE

GOTO :EOF

:HELL
make -f WindowsGCC.mak clean

make -f WindowsGCC.mak ALL
---------------------------------------------------------------------------------------------------------------------

Windows visual studio 範例 vc2005.bat
---------------------------------------------------------------------------------------------------------------------
@echo off

IF EXIST "%VS80COMNTOOLS%vsvars32.bat" (
call "%VS80COMNTOOLS%vsvars32.bat"
GOTO HELL
)


ECHO can not find visual studio
PAUSE

GOTO :EOF

:HELL
NMAKE /f "WindowsVC.mak" clean

NMAKE /f "WindowsVC.mak" ALL
---------------------------------------------------------------------------------------------------------------------

Linux gcc 範例 gcc.sh
---------------------------------------------------------------------------------------------------------------------
make -f ./Makefile clean
make -f ./Makefile all
--------------------------------------------------------------------------------------------------------------------- 

openSSL 1.0.1e 編譯

0. 現成編好的
http://slproweb.com/products/Win32OpenSSL.html

1. 必要條件
openssl source code (使用版本為 openssl-1.0.1e)
activeperl
NASM (非必要, 有會比較快, 快在哪? ...阿栽.)
Microsoft Visual Studio (這邊用的為 vs2005)

2. 編譯環境
安裝 activeperl, NASM, 將 NASM 安裝路徑加入系統path裡

開啟 程式集->Microsoft Visual Studio 2005->Visual Studio Tools->Visual Studio 2005 Command Prompt
(編譯X64 就開啟 Visual Studio 2005 x64 Win64 Command Prompt, IA64依此類推)
* 2005 64bit compiler 預設是沒安裝的, 要用記得安裝一下

3. 移動到目錄
>cd D:\openssl-1.0.1e

4. 指定編譯類型
X86
>perl Configure VC-WIN32 no-asm
or
>perl Configure VC-WIN32

X64
>perl Configure VC-WIN64A no-asm

IA64
>perl Configure VC-WIN64I no-asm

5. 製造編譯用 *.mak 檔
X86
>ms\do_ms.bat
or
>ms\do_nasm.bat

X64
>ms\do_win64a.bat

IA64
>ms\do_win64i.bat

6. 編譯
先修改 ms\ntdll.mak , 將 CFLAG= /MD ... 改為 CFLAG= /MT ...
nmake -f ms\ntdll.mak   動態連結
or
nmake -f ms\nt.mak      靜態連結

7. 產出
D:\openssl-1.0.1e\outdll32
or
D:\openssl-1.0.1e\out32

ssleay32.lib    實現SSL協議
libeay32.lib    實現各種演算法

8. 懶人用 batch

REM VS2005 X86
@echo off

IF NOT EXIST "%VS80COMNTOOLS%vsvars32.bat" (
ECHO can not find visual studio 2005
PAUSE
GOTO :EOF
)

call "%VS80COMNTOOLS%vsvars32.bat"

SET OPENSSLDIR=.\openssl-1.0.1e
SET OUTPUTDIR=.\OpenSSL_VC2005_X86

CD %OPENSSLDIR%
perl Configure VC-WIN32
start /wait cmd.exe /c .\ms\do_nasm.bat
nmake -f .\ms\nt.mak
nmake -f .\ms\nt.mak clean
CD ..

IF EXIST %OUTPUTDIR% (
DEL %OUTPUTDIR%\libeay32.lib
DEL %OUTPUTDIR%\ssleay32.lib
DEL %OUTPUTDIR%\openssl.exe
) else (
MKDIR %OUTPUTDIR%
)

COPY %OPENSSLDIR%\out32\libeay32.lib %OUTPUTDIR%\libeay32.lib
COPY %OPENSSLDIR%\out32\ssleay32.lib %OUTPUTDIR%\ssleay32.lib
COPY %OPENSSLDIR%\out32\openssl.exe  %OUTPUTDIR%\openssl.exe

DEL %OPENSSLDIR%\out32\libeay32.lib
DEL %OPENSSLDIR%\out32\ssleay32.lib
DEL %OPENSSLDIR%\out32\openssl.exe


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

REM VS2005 X64
@echo off

SET CompilerBat="C:\Program Files\Microsoft Visual Studio 8\VC\bin\amd64\vcvarsamd64.bat"
IF EXIST %CompilerBat% (
CALL %CompilerBat%
GOTO BuildProject
}

SET CompilerBat="C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin\amd64\vcvarsamd64.bat"
IF EXIST %CompilerBat% (
CALL %CompilerBat%
GOTO BuildProject
)

ECHO can not find visual studio 2005
PAUSE
GOTO :EOF

:BuildProject

SET OPENSSLDIR=.\openssl-1.0.1e
SET OUTPUTDIR=.\OpenSSL_VC2005_X64

CD %OPENSSLDIR%
perl Configure VC-WIN64A no-asm
start /wait cmd.exe /c .\ms\do_win64a.bat
nmake -f .\ms\nt.mak
nmake -f .\ms\nt.mak clean
CD ..

IF EXIST %OUTPUTDIR% (
DEL %OUTPUTDIR%\libeay32.lib
DEL %OUTPUTDIR%\ssleay32.lib
DEL %OUTPUTDIR%\openssl.exe
) else (
MKDIR %OUTPUTDIR%
)

COPY %OPENSSLDIR%\out32\libeay32.lib %OUTPUTDIR%\libeay32.lib
COPY %OPENSSLDIR%\out32\ssleay32.lib %OUTPUTDIR%\ssleay32.lib
COPY %OPENSSLDIR%\out32\openssl.exe  %OUTPUTDIR%\openssl.exe

DEL %OPENSSLDIR%\out32\libeay32.lib
DEL %OPENSSLDIR%\out32\ssleay32.lib
DEL %OPENSSLDIR%\out32\openssl.exe 


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

2014年12月8日 星期一

python 上一個簡單的 trace tools

寫程式時很怕測試人員沒頭沒尾的回報, 還是丟了一個用克林貢語寫的 bug 描述.

所以我都會額外自己發展一個小工具讓程序輸出 log, 讓測試人員回報用.

ptlog.py

#-------------------------------------------------------------------------------
# Name:        ptlog
# Purpose:
#
# Author:      nanoha
#
# Created:     10/12/2013
# Copyright:   (c) nanoha 2013
# Licence:     no licence
#-------------------------------------------------------------------------------

import os, inspect, sys
from time import strftime

__author__  = "nanoha <nanoha@nanoha.org>"
__status__  = "production"
__version__ = "0.0.6.0"
__date__    = "2014-05-07"

__IsPrint = True

if (os.name == 'nt'):
    __output = u'C:\\temp\\pt.txt'
elif (os.name == 'posix'):
    __output = u'/temp/pt.txt'

def SetOutput(szLog):
    global __output
    __output = szLog

def IsPrint(bPrint):
    global __IsPrint
    __IsPrint = bPrint

def __WriteFile(szFileName, szFuncName, szMsgline, szFlag, szMsg):
    hFile = None
    try:
        now = strftime('%Y-%m-%d %H:%M:%S')
        szFormatMsg = '[%s][%s][%s][%s][%s]%s\n' % ( now, szFileName, szFuncName, szMsgline, szFlag, szMsg)
        hFile = open(__output, 'a+')
        hFile.write(szFormatMsg)
    except Exception as error:
        try:
            now = strftime('%Y-%m-%d %H:%M:%S')
            szFormatMsg = u'[%s][%s][%s][%s][%s]%s\n' % (unicode(now), unicode(szFileName), unicode(szFuncName), unicode(szMsgline), unicode(szFlag), unicode(error))
            hFile = open(__output, 'a+')
            hFile.write(szFormatMsg.encode('utf-8'))
        except Exception as error:
            print error
    finally:
        if hFile:
            hFile.close()


def PTError(szMsg):
    try:
        Callerframel = inspect.stack()[1][0]
        if (__IsPrint):
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'PTERROR', szMsg)
        if (os.path.exists(__output)):
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'PTERROR', szMsg)
    except Exception as error:
        pass

def convertToStr(szMsg):
    ret = ''
    try:
        if isinstance(szMsg, unicode):
            ret = szMsg.encode('utf-8')
        elif isinstance(szMsg, str):
            ret = szMsg
    except Exception as error:
        PTError(str(error))
    finally:
        return ret

def debug(szMsg):
    Callerframel = inspect.stack()[1][0]
    if (__IsPrint):
        try:
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'DEBUG', szMsg)
        except Exception as error:
            PTError(str(error))

    if (os.path.exists(__output)):
        szMsg = convertToStr(szMsg)
        if szMsg:
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'DEBUG', szMsg)

def info(szMsg):
    Callerframel = inspect.stack()[1][0]
    if (__IsPrint):
        try:
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'INFO', szMsg)
        except Exception as error:
            PTError(str(error))

    if (os.path.exists(__output)):
        szMsg = convertToStr(szMsg)
        if szMsg:
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'INFO', szMsg)

def warning(szMsg):
    Callerframel = inspect.stack()[1][0]
    if (__IsPrint):
        try:
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'WARNING', szMsg)
        except Exception as error:
            PTError(str(error))

    if (os.path.exists(__output)):
        szMsg = convertToStr(szMsg)
        if szMsg:
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'WARNING', szMsg)

def error(szMsg):
    Callerframel = inspect.stack()[1][0]
    if (__IsPrint):
        try:
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'ERROR', szMsg)
        except Exception as error:
            PTError(str(error))

    if (os.path.exists(__output)):
        szMsg = convertToStr(szMsg)
        if szMsg:
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'ERROR', szMsg)

def critical(szMsg):
    Callerframel = inspect.stack()[1][0]
    if (__IsPrint):
        try:
            print '[%s][%s][%s][%s]%s' % (Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'CRITICAL', szMsg)
        except Exception as error:
            PTError(str(error))

    if (os.path.exists(__output)):
        szMsg = convertToStr(szMsg)
        if szMsg:
            __WriteFile(Callerframel.f_code.co_filename, Callerframel.f_code.co_name, Callerframel.f_lineno, 'CRITICAL', szMsg)
#-------------------------------------------------------------------------------

測試, 如果 C:\\temp\\pt.txt 不存在則不輸出,
要輸出別的名稱可用 ptlog.SetOutput('.\\a.txt')
#-------------------------------------------------------------------------------
import ptlog

def main():
    ptlog.debug('test 1')
    ptlog.info('test 2')
    ptlog.warning('test 3')
    ptlog.error('test 4')
    ptlog.critical('test 5')

if __name__ == '__main__':
    main()

#-------------------------------------------------------------------------------

獲取 windows 上安裝的所有 browser

上頭丟了一個奇怪的需求, 說我們軟件開啟的網頁要能指定 browser.

當下只有 囧 可以形容.


要知道什麼軟件是瀏覽器, 目前大概只能針對已知的 browser 個別處理.

首先要做的是就是先獲取 browser 執行檔的路徑.

所有 browser 安裝後一定會產生 Shortcut, 從 Shortcut 取得就ok了

1. 所以先取得所有 *.lnk 在 start menu下的.

wchar_t szPath[MAX_PATH];
CFileInfoList files;

memset(szPath, 0x00, sizeof(szPath));
if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_PROGRAMS, false))
{
    files.GetFolderInfo(szPath);
}

memset(szPath, 0x00, sizeof(szPath));
if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_COMMON_PROGRAMS, false))
{
   files.GetFolderInfo(szPath);

}

2. 接著寫取得快捷路徑的方法:
BOOL GetShortcutTarget(const wchar_t *file, CString &szTarget)
{
    HRESULT hr;
    IShellLinkW *pLink;  //IShellLink对象指针
    IPersistFile *ppf;  //IPersisFil对象指针
    wchar_t szPah[MAX_PATH];
    WIN32_FIND_DATAW FileData;

    szTarget.Empty();

    hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void**)&pLink);
    if (FAILED(hr))
    {
        SAVELOG_DANGER("CoCreateInstance failed");
        return FALSE;
    }

    //从IShellLink对象中获取IPersistFile接口
    hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf); 
    if (FAILED(hr)) 
    {
        SAVELOG_DANGER("QueryInterface failed");
        pLink->Release(); 
        return FALSE; 
    }

    // open Shortcut
    hr = ppf->Load(file, STGM_READ);
    if (SUCCEEDED(hr))
    {
        memset(szPah, 0x00, sizeof(szPah));
        hr = pLink->GetPath(szPah, MAX_PATH, &FileData, SLGP_SHORTPATH);
        if (SUCCEEDED(hr))
        {
            szTarget = szPah;
        }
    }

    ppf->Release(); 
    pLink->Release();
    return SUCCEEDED(hr);
}


3. 針對特定名稱快捷取路徑
Internet Explorer.lnk
Mozilla Firefox.lnk
Waterfox.lnk
Navigator.lnk
Pale Moon.lnk
SeaMonkey.lnk
Google Chrome.lnk
Safari.lnk
Opera.lnk

4. 針對 Safari 處理
   Safari 的快捷長的不大一樣, 所以取不到路徑, 改成取 Working Directory 並加檔案名稱

BOOL GetShortcutWorkDirectory(const wchar_t *file, CString &szDir)
{
    HRESULT hr;
    IShellLinkW *pLink;  //IShellLink对象指针
    IPersistFile *ppf;  //IPersisFil对象指针
    wchar_t szPah[MAX_PATH];
    WIN32_FIND_DATAW FileData;

    szDir.Empty();

    hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void**)&pLink);
    if (FAILED(hr))
    {
        SAVELOG_DANGER("CoCreateInstance failed");
        return FALSE;
    }

    //从IShellLink对象中获取IPersistFile接口
    hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);
    if (FAILED(hr))
    {
        SAVELOG_DANGER("QueryInterface failed");
        pLink->Release();
        return FALSE;
    }

    // open Shortcut
    hr = ppf->Load(file, STGM_READ);
    if (SUCCEEDED(hr))
    {
        memset(szPah, 0x00, sizeof(szPah));
        hr = pLink->GetWorkingDirectory(szPah, MAX_PATH);
        if (SUCCEEDED(hr))
        {
            szDir = szPah;
        }
    }

    ppf->Release();
    pLink->Release();
    return SUCCEEDED(hr);
}


5. 最後成果

    // define by windows
    unit = new CBrowserList::CBrowserInfo();
    unit->m_Name = PTwcsdup(g_Language.GetString("default", "Default"));
    unit->m_Path = PTwcsdup(L"");
    this->m_list.Add(unit);

    memset(szPath, 0x00, sizeof(szPath));
    if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_PROGRAMS, false))
    {
        files.GetFolderInfo(szPath);
        for (i=0; i<files.Count(); i++)
        {
            _GetFileName(files[i]->fullName, FileName);
            if (0 == FileName.CompareNoCase(L"Internet Explorer.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Internet Explorer");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);               
                }

            }
        }
    }

    memset(szPath, 0x00, sizeof(szPath));
    if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_COMMON_PROGRAMS, false))
    {
        files.GetFolderInfo(szPath);
        for (i=0; i<files.Count(); i++)
        {
            _GetFileName(files[i]->fullName, FileName);
            if (0 == FileName.CompareNoCase(L"Mozilla Firefox.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Mozilla Firefox");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                   
                }

            }
            else if (0 == FileName.CompareNoCase(L"Waterfox.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Waterfox");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                   
                }      
     
            }
            else if (0 == FileName.CompareNoCase(L"Navigator.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Navigator");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                   
                }           

            }
            else if (0 == FileName.CompareNoCase(L"Pale Moon.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Pale Moon");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                   
                }   
        
            }
            else if (0 == FileName.CompareNoCase(L"SeaMonkey.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"SeaMonkey");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                   
                } 
          
            }
            else if (0 == FileName.CompareNoCase(L"Google Chrome.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Google Chrome");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                  
                }

            }
            else if (0 == FileName.CompareNoCase(L"Safari.lnk"))
            {
                if (GetShortcutWorkDirectory(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Safari");
                    unit->m_Path = PTwcsdup(Target);
                    unit->m_Path = PTwcscat(unit->m_Path, L"Safari.exe");
                    this->m_list.Add(unit);                   
                }

            }
            else if (0 == FileName.CompareNoCase(L"Opera.lnk"))
            {
                if (GetShortcutTarget(files[i]->fullName, Target))
                {
                    unit = new CBrowserList::CBrowserInfo();
                    unit->m_Name = PTwcsdup(L"Opera");
                    unit->m_Path = PTwcsdup(Target);
                    this->m_list.Add(unit);                
                }

            }
        }
    }


6. 呼叫
void openURL(const wchar_t *url)
{
    if (g_SettingsInfo.Browser.IsEmpty())
    {
        ShellExecuteW(NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
        return;
    }
    // check Browser was exist
    if (FileExists(g_SettingsInfo.Browser.GetString()))
    {
        ShellExecuteW(NULL, NULL, g_SettingsInfo.Browser.GetString(), url, NULL, SW_SHOWNORMAL);
        return;
    }
    //
    ShellExecuteW(NULL, _T("open"), url, NULL, NULL, SW_SHOWNORMAL);
}


libwdi 1.2.4 編譯

OS: Fedora 20
compiler: MinGW
Source: zadig

目前 Spice-gtk 的 USB redirection功能在 windows 下無法作用, 目標將 Spice-gtk 與 libwdi 融合, 讓 windows 下此功能也能運作, 首先讓 libwdi 在 Fedora 下也能編譯(配合 virt-viewer).

1. 建置環境
    安裝完 Fedora 完後,安裝 MinGW.
        sudo yum install mingw*

2. 設定與編譯
    1. 下載  libusb-win32
         這邊使用的版本為 libusb-win32-bin-1.2.6.0
    2.  下載 libusbK
         這邊使用的版本為 libusbK-3.0.5.16-bin
    3. 下載 WinDDK 7.1
         這邊使用的版本為 7600.16385.1
    4. 設定參考路徑
         請根據下載檔案的解壓縮位置設定
         EX: mingw32-configure --with-ddkdir="/home/jojo/桌面/7600.16385.1" --with-libusb0="/home/jojo/桌面/libusb-win32-bin-1.2.6.0" --with-libusbk="/home/jojo/桌面/libusbK-3.0.5.16-bin/bin"
    5. 修改 config.h
        修改或新增以下定義
        #define COINSTALLER_DIR "wdf"
        #define WDF_VER 1009

        #define OPT_M64
    6. 編譯的時候會說找不到 winusbcoinstaller2.dll
         複製 7600.16385.1/redist/winusb/x86/winusbcoinstaller2.dll 到 7600.16385.1/redist/wdf/x86/winusbcoinstaller2.dll
    7. 編譯
        mingw32-make
    8. 安裝
        sudo mingw32-make install
    9. 產出 
        在 /usr/i686-w64-mingw32/sys-root/mingw/lib
        libwdi.la
        libwdi.a
        libwdi.dll.a
        在 /usr/i686-w64-mingw32/sys-root/mingw/bin
        libwdi.dll

    10. 測試在 libwdi.dll 沒有含 x64 installer, 所以還是拿 windows 下 build 出的 dll 用.

wxPython transparent 一些簡單的透明元件

最近玩 wxPython 3時覺得沒有透明元件覺得就用不下去了, 所以設計了些個簡單的透明元件.


TPanel
TStaticText
TButton

但是寫完之後, 發現還很多元件待寫...等有用到再寫了...囧

#-------------------------------------------------------------------------------
# Name:        ExtComponent
# Purpose:     simple transparent components for Python 2.7
#
# Author:      nanoha
#
# Created:     01/01/3000
# Copyright:   (c) nanoha 3000
# Licence:     no licence
#-------------------------------------------------------------------------------
import wx
################################################################################
class TPanel(wx.Panel):
    def __init__(self, parent, id=-1, image=None, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=wx.TAB_TRAVERSAL, name="panel"):
        style |= (wx.CLIP_CHILDREN | wx.TRANSPARENT_WINDOW)
        wx.Panel.__init__(self, parent, id, pos, size, style, name)
        self.SetBackedImage(image)
        self.Bind(wx.EVT_PAINT,self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
    # 設定背景圖片
    def SetBackedImage(self, image=None):
        if image is not None:
            self.BackedImage = image
            tmpImg = self.BackedImage.Copy()
            W, H = self.GetClientSize()
            tmpImg.Rescale(W, H)
            self.BackedBmp = tmpImg.ConvertToBitmap()
        else:
            self.BackedBmp = None
            self.BackedImage = None
        self.Refresh()

    def OnPaint(self,event):
        event.Skip()
        (width, height) = self.GetClientSizeTuple()
        dc = wx.PaintDC(self)
        self.DrawBackedImage(dc, width, height)

    def DrawBackedImage(self, dc, width, height):
        # 建立繪圖緩衝區
        bmp = wx.EmptyBitmap(width, height)
        memDC = wx.MemoryDC()
        memDC.SelectObject(bmp)
        # 塗滿透明色
        memDC.SetPen(wx.Pen('#010101'))
        memDC.SetBrush(wx.Brush('#010101'))
        memDC.DrawRectangle(0, 0, width, height)
        # 加入父窗口背景
        Parent = self.GetParent()
        if Parent:
            # 加入父窗口背景色
            ParentClr = Parent.GetBackgroundColour()
            memDC.SetPen(wx.Pen(ParentClr))
            memDC.SetBrush(wx.Brush(ParentClr))
            memDC.DrawRectangle(0, 0, width, height)
            # 加入父窗口背景圖
            if hasattr(Parent, 'BackedBmp'):
                if Parent.BackedBmp:
                    # get position
                    scr_x,scr_y = self.GetScreenPositionTuple()
                    x,y = Parent.ScreenToClientXY(scr_x,scr_y)
                    pbmp_W = Parent.BackedBmp.GetWidth()
                    pbmp_H = Parent.BackedBmp.GetHeight()
                    w1 = pbmp_W-x
                    if width < w1:
                        w1 = width
                    h1 = pbmp_H-y
                    if height < h1:
                        h1 = height
                    if w1>0 and h1>0:
                        pbackDC = wx.MemoryDC(Parent.BackedBmp)
                        memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
                        pbackDC.SelectObject(wx.NullBitmap)
        # 加入自帶背景
        if self.BackedBmp:
            bmp_W = self.BackedBmp.GetWidth()
            bmp_H = self.BackedBmp.GetHeight()
            backDC = wx.MemoryDC(self.BackedBmp)
            memDC.Blit(0, 0, bmp_W, bmp_H, backDC, 0, 0)
            backDC.SelectObject(wx.NullBitmap)
        memDC.SelectObject(wx.NullBitmap)
        # 設定透明色
        mask = wx.Mask(bmp, wx.Colour(1,1,1))
        bmp.SetMask(mask)
        # 畫下去
        dc.DrawBitmap(bmp, 0, 0, True)
    # 將背景圖填滿 panel
    def OnSize(self,event):
        if self.BackedImage is None:
            return
        W, H = self.GetClientSize()
        if W == 0 or H == 0:
            return
        bmp_W = self.BackedBmp.GetWidth()
        bmp_H = self.BackedBmp.GetHeight()
        if W != bmp_W or H != bmp_H:
            tmpImg = self.BackedImage.Copy()
            tmpImg.Rescale(W, H)
            self.BackedBmp = tmpImg.ConvertToBitmap()
            self.Refresh()
################################################################################
TST_TEXT_LEFT   = 0
TST_TEXT_CENTER = 1
TST_TEXT_RIGHT  = 2

class TStaticText(wx.StaticText):
    def __init__(self,parent,id,label='',
                 pos=wx.DefaultPosition,
                 size=wx.DefaultSize,
                 style=0,
                 labelpos=TST_TEXT_LEFT,
                 name = 'TPStaticText'):
        style |= wx.TRANSPARENT_WINDOW
        wx.StaticText.__init__(self,parent,id,label,pos,size,style=style)
        self.labelpos=labelpos
        self.Bind(wx.EVT_PAINT,self.OnPaint)

    def OnPaint(self,event):
        event.Skip()
        (width, height) = self.GetClientSizeTuple()
        # 建立繪圖緩衝區
        bmp = wx.EmptyBitmap(width, height)
        memDC = wx.MemoryDC()
        memDC.SelectObject(bmp)
        # 塗滿透明色
        memDC.SetPen(wx.Pen('#010101'))
        memDC.SetBrush(wx.Brush('#010101'))
        memDC.DrawRectangle(0, 0, width, height)
        # 加入父窗口背景
        Parent = self.GetParent()
        if Parent:
            # 加入父窗口背景色
            ParentClr = Parent.GetBackgroundColour()
            memDC.SetPen(wx.Pen(ParentClr))
            memDC.SetBrush(wx.Brush(ParentClr))
            memDC.DrawRectangle(0, 0, width, height)
            # 加入父窗口背景圖
            if hasattr(Parent, 'BackedBmp'):
                if Parent.BackedBmp:
                    # get position
                    scr_x,scr_y = self.GetScreenPositionTuple()
                    x,y = Parent.ScreenToClientXY(scr_x,scr_y)
                    pbmp_W = Parent.BackedBmp.GetWidth()
                    pbmp_H = Parent.BackedBmp.GetHeight()
                    w1 = pbmp_W-x
                    if width < w1:
                        w1 = width
                    h1 = pbmp_H-y
                    if height < h1:
                        h1 = height
                    if w1>0 and h1>0:
                        pbackDC = wx.MemoryDC(Parent.BackedBmp)
                        memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
                        pbackDC.SelectObject(wx.NullBitmap)
        # 加入文字
        textXpos = textYpos = 0
        textWidth, textHeight = self.GetTextExtent(self.GetLabel())
        textYpos = (height-textHeight)/2
        if self.labelpos == TST_TEXT_CENTER:
            textXpos = (width-textWidth)/2
        elif self.labelpos == TST_TEXT_RIGHT:
            textXpos = width-textWidth
        memDC.SetFont(self.GetFont())
        #if self.IsEnabled():
        memDC.SetTextForeground(self.GetForegroundColour())
        #else:
        #    memDC.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
        memDC.DrawText(self.GetLabel(), textXpos, textYpos)
        memDC.SelectObject(wx.NullBitmap)
        # 設定透明色
        mask = wx.Mask(bmp, wx.Colour(1,1,1))
        bmp.SetMask(mask)
        # 畫下去
        dc = wx.PaintDC(self)
        dc.DrawBitmap(bmp, 0, 0, True)
################################################################################
class TButtonEvent(wx.PyCommandEvent):
    def __init__(self, eventType, id):
        wx.PyCommandEvent.__init__(self, eventType, id)
        self.isDown = False
        self.theButton = None
    def SetIsDown(self, isDown):
        self.isDown = isDown
    def GetIsDown(self):
        return self.isDown
    def SetButtonObj(self, btn):
        self.theButton = btn
    def GetButtonObj(self):
        return self.theButton
################################################################################
TBB_IMAGE_CENTER = 0
TBB_IMAGE_LEFT   = 1
TBB_IMAGE_RIGHT  = 2
TBB_IMAGE_TOP    = 3
TBB_IMAGE_BOTTOM = 4

TBB_LABEL_CENTER = 0
TBB_LABEL_LEFT   = 1
TBB_LABEL_RIGHT  = 2
TBB_LABEL_TOP    = 3
TBB_LABEL_BOTTOM = 4

class TBitmapButton(wx.PyControl):
    def __init__(self, parent=None, id=-1, image=None, label='',
                 pos = wx.DefaultPosition, size = wx.DefaultSize,
                 style=0, imagepos = TBB_IMAGE_CENTER,
                 labelpos = TBB_LABEL_CENTER,
                 validator = wx.DefaultValidator,
                 name = "Nanohabutton"):
        cstyle = style# | wx.BORDER_NONE
        wx.PyControl.__init__(self, parent, id, pos, size, cstyle, validator, name)

        self.up = True
        self.hasFocus = False
        self.style = cstyle
        if cstyle & wx.BORDER_NONE:
            self.bezelWidth = 0
            self.useFocusInd = False
        else:
            self.bezelWidth = 2
            self.useFocusInd = True

        self.ImagePos = imagepos
        self.LabelPos = labelpos

        self.BackedBmp = None
        if image is not None:
            self.BackedBmp = image.ConvertToBitmap()

        self.MaskClr = wx.Colour(1,1,1)

        self.SetLabel(label)
        self.InheritAttributes()
        self.SetInitialSize(size)
        self.InitColours()

        self.Bind(wx.EVT_LEFT_DOWN,        self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP,          self.OnLeftUp)
        self.Bind(wx.EVT_LEFT_DCLICK,      self.OnLeftDown)
        self.Bind(wx.EVT_MOTION,           self.OnMotion)
        self.Bind(wx.EVT_SET_FOCUS,        self.OnGainFocus)
        self.Bind(wx.EVT_KILL_FOCUS,       self.OnLoseFocus)
        self.Bind(wx.EVT_KEY_DOWN,         self.OnKeyDown)
        self.Bind(wx.EVT_KEY_UP,           self.OnKeyUp)
        self.Bind(wx.EVT_PAINT,            self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackgound)
        self.Bind(wx.EVT_SIZE,             self.OnSize)

    def SetInitialSize(self, size=None):
        if size is None:
            size = wx.DefaultSize
        wx.PyControl.SetInitialSize(self, size)
    SetBestSize = SetInitialSize

    def DoGetBestSize(self):
        w, h, useMin = self._GetLabelSize()
        if self.style & wx.BU_EXACTFIT:
            width = w + 2 + 2 * self.bezelWidth + 4 * int(self.useFocusInd)
            height = h + 2 + 2 * self.bezelWidth + 4 * int(self.useFocusInd)
        else:
            defSize = wx.Button.GetDefaultSize()
            width = 12 + w
            if useMin and width < defSize.width:
                width = defSize.width
            height = 11 + h
            if useMin and height < defSize.height:
                height = defSize.height
            width = width + self.bezelWidth - 1
            height = height + self.bezelWidth - 1
        return (width, height)

    def AcceptsFocus(self):
        return self.IsShown() and self.IsEnabled()

    def GetDefaultAttributes(self):
        return wx.Button.GetClassDefaultAttributes()

    def ShouldInheritColours(self):
        return False

    def Enable(self, enable=True):
        if enable != self.IsEnabled():
            wx.PyControl.Enable(self, enable)
            self.Refresh()

    def SetBezelWidth(self, width):
        self.bezelWidth = width

    def GetBezelWidth(self):
        return self.bezelWidth

    def SetUseFocusIndicator(self, flag):
        self.useFocusInd = flag

    def GetUseFocusIndicator(self):
        return self.useFocusInd

    def InitColours(self):
        faceClr = self.GetBackgroundColour()
        r, g, b = faceClr.Get()
        fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
        self.faceDnClr = wx.Colour(fr, fg, fb)
        sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
        self.shadowPenClr = wx.Colour(sr,sg,sb)
        hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
        self.highlightPenClr = wx.Colour(hr,hg,hb)
        self.focusClr = wx.Colour(hr, hg, hb)

    def SetBackgroundColour(self, colour):
        wx.PyControl.SetBackgroundColour(self, colour)
        self.InitColours()

    def SetForegroundColour(self, colour):
        wx.PyControl.SetForegroundColour(self, colour)
        self.InitColours()

    def SetDefault(self):
        tlw = wx.GetTopLevelParent(self)
        if hasattr(tlw, 'SetDefaultItem'):
            tlw.SetDefaultItem(self)

    def _GetLabelSize(self):
        w, h = self.GetTextExtent(self.GetLabel())
        if not self.BackedBmp:
            return w, h, True

        w_bmp = self.BackedBmp.GetWidth() + 2
        h_bmp = self.BackedBmp.GetHeight() + 2
        height = h + h_bmp + 12
        if w_bmp > w:
            width = w_bmp
        else:
            width = w
        return width, height, True

    def Notify(self):
        evt = ExtButtonEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
        evt.SetIsDown(not self.up)
        evt.SetButtonObj(self)
        evt.SetEventObject(self)
        self.GetEventHandler().ProcessEvent(evt)

    def DrawBezel(self, dc, x1, y1, x2, y2):
        # draw the upper left sides
        if self.up:
            dc.SetPen(wx.Pen(self.highlightPenClr, 1, wx.SOLID))
        else:
            dc.SetPen(wx.Pen(self.shadowPenClr, 1, wx.SOLID))
        for i in range(self.bezelWidth):
            dc.DrawLine(x1+i, y1, x1+i, y2-i)
            dc.DrawLine(x1, y1+i, x2-i, y1+i)
        # draw the lower right sides
        if self.up:
            dc.SetPen(wx.Pen(self.shadowPenClr, 1, wx.SOLID))
        else:
            dc.SetPen(wx.Pen(self.highlightPenClr, 1, wx.SOLID))
        for i in range(self.bezelWidth):
            dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
            dc.DrawLine(x2-i, y1+i, x2-i, y2)

    def DrawBackedImage(self, dc, width, height, dx=0, dy=0):
        x1 = y1 = 0
         # 建立繪圖緩衝區
        bmp = wx.EmptyBitmap(width, height)
        memDC = wx.MemoryDC()
        memDC.SelectObject(bmp)
        # 塗滿透明色
        memDC.SetPen(wx.Pen(self.MaskClr))
        memDC.SetBrush(wx.Brush(self.MaskClr))
        memDC.DrawRectangle(0, 0, width, height)
        # 加入父窗口背景
        Parent = self.GetParent()
        if Parent:
            # 加入父窗口背景色
            ParentClr = Parent.GetBackgroundColour()
            memDC.SetPen(wx.Pen(ParentClr))
            memDC.SetBrush(wx.Brush(ParentClr))
            memDC.DrawRectangle(0, 0, width, height)
            # 加入父窗口背景圖
            if hasattr(Parent, 'BackedBmp'):
                if Parent.BackedBmp:
                    # get position
                    scr_x,scr_y = self.GetScreenPositionTuple()
                    x,y = Parent.ScreenToClientXY(scr_x,scr_y)
                    pbmp_W = Parent.BackedBmp.GetWidth()
                    pbmp_H = Parent.BackedBmp.GetHeight()
                    w1 = pbmp_W-x
                    if width < w1:
                        w1 = width
                    h1 = pbmp_H-y
                    if height < h1:
                        h1 = height
                    if w1>0 and h1>0:
                        pbackDC = wx.MemoryDC(Parent.BackedBmp)
                        memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
                        pbackDC.SelectObject(wx.NullBitmap)
        # 加入自帶背景
        if self.BackedBmp:
            bmp_W = self.BackedBmp.GetWidth()
            bmp_H = self.BackedBmp.GetHeight()
            backDC = wx.MemoryDC(self.BackedBmp)
            # 背景位置
            if TBB_IMAGE_LEFT == self.ImagePos:
                x1 = dx
                y1 = (height-bmp_H)/2+dy
            elif TBB_IMAGE_RIGHT == self.ImagePos:
                x1 = width-bmp_W+dx
                y1 = (height-bmp_H)/2+dy
            elif TBB_IMAGE_TOP == self.ImagePos:
                x1 = (width-bmp_W)/2+dx
                y1 = dy
            elif TBB_IMAGE_BOTTOM == self.ImagePos:
               x1 = (width-bmp_W)/2+dx
               y1 = height-bmp_H+dy
            else:
               x1 = (width-bmp_W)/2+dx
               y1 = (height-bmp_H)/2+dy
            memDC.Blit(x1, y1, bmp_W, bmp_H, backDC, 0, 0)
            backDC.SelectObject(wx.NullBitmap)
            self.DrawBackedImage2(memDC, dx, dy)
        # 邊框
        x1 = y1 = 0
        x2 = width-1
        y2 = height-1
        self.DrawBezel(memDC, x1, y1, x2, y2)
        # 加入文字
        memDC.SetFont(self.GetFont())
        if self.IsEnabled():
            memDC.SetTextForeground(self.GetForegroundColour())
        else:
            memDC.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
        label = self.GetLabel()
        tw, th = memDC.GetTextExtent(label)
        # 文字位置
        if TBB_LABEL_LEFT == self.LabelPos:
            x1 = dx
            y1 = (height-th)/2+dy
        elif TBB_LABEL_RIGHT == self.LabelPos:
            x1 = width-tw+dx
            y1 = (height-th)/2+dy
        elif TBB_LABEL_TOP == self.LabelPos:
            x1 = (width-tw)/2+dx
            y1 = dy
        elif TBB_LABEL_BOTTOM == self.LabelPos:
            x1 = (width-tw)/2+dx
            y1 = height-th+dy
        else:
            x1 = (width-tw)/2+dx
            y1 = (height-th)/2+dy
        memDC.DrawText(label, x1, y1)
        # 加入Focus效果
        if self.hasFocus and self.useFocusInd:
            self.DrawFocusIndicator(memDC, width, height)
        memDC.SelectObject(wx.NullBitmap)
        # 設定透明色
        mask = wx.Mask(bmp, self.MaskClr)
        bmp.SetMask(mask)
        # 畫下去
        hasMask = bmp.GetMask() is not None
        dc.DrawBitmap(bmp, 0, 0, hasMask)

    def DrawBackedImage2(self, dc, dx=0, dy=0):
        pass

    def DrawFocusIndicator(self, dc, w, h):
        bw = self.bezelWidth
        textClr = self.GetForegroundColour()
        focusIndPen = wx.Pen(textClr, 1, wx.USER_DASH)
        focusIndPen.SetDashes([1,1])
        focusIndPen.SetCap(wx.CAP_BUTT)

        if wx.Platform == "__WXMAC__":
            dc.SetLogicalFunction(wx.XOR)
        else:
            focusIndPen.SetColour(self.focusClr)
            dc.SetLogicalFunction(wx.INVERT)
        dc.SetPen(focusIndPen)
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        dc.DrawRectangle(bw+2,bw+2,  w-bw*2-4, h-bw*2-4)
        dc.SetLogicalFunction(wx.COPY)

    def OnPaint(self, event):
        (width, height) = self.GetClientSizeTuple()
        dx = dy = 0
        if not self.up:
            dx = dy = 1
        dc = wx.PaintDC(self)
        #dc.SetBackground(wx.TRANSPARENT_BRUSH)
        #dc.Clear()
        self.DrawBackedImage(dc, width, height, dx, dy)

    def OnSize(self, event):
        self.Refresh()
        event.Skip()

    def OnEraseBackgound(self, event):
        pass

    def OnLeftDown(self, event):
        if not self.IsEnabled():
            return
        self.up = False
        self.CaptureMouse()
        self.SetFocus()
        self.Refresh()
        event.Skip()

    def OnLeftUp(self, event):
        if not self.IsEnabled() or not self.HasCapture():
            return
        if self.HasCapture():
            self.ReleaseMouse()
            if not self.up:    # if the button was down when the mouse was released...
                self.Notify()
            self.up = True
            if self:           # in case the button was destroyed in the eventhandler
                self.Refresh()
                event.Skip()

    def OnMotion(self, event):
        if not self.IsEnabled() or not self.HasCapture():
            return
        if event.LeftIsDown() and self.HasCapture():
            x,y = event.GetPositionTuple()
            w,h = self.GetClientSizeTuple()
            if self.up and x<w and x>=0 and y<h and y>=0:
                self.up = False
                self.Refresh()
                return
            if not self.up and (x<0 or y<0 or x>=w or y>=h):
                self.up = True
                self.Refresh()
                return
        event.Skip()

    def OnGainFocus(self, event):
        self.hasFocus = True
        self.Refresh()
        self.Update()

    def OnLoseFocus(self, event):
        self.hasFocus = False
        self.Refresh()
        self.Update()

    def OnKeyDown(self, event):
        if self.hasFocus and event.GetKeyCode() == ord(" "):
            self.up = False
            self.Refresh()
        event.Skip()

    def OnKeyUp(self, event):
        if self.hasFocus and event.GetKeyCode() == ord(" "):
            self.up = True
            self.Notify()
            self.Refresh()
        event.Skip()
################################################################################