[轉載]清除無主套件及套件安裝暫存檔

http://renlife.wordpress.com/2007/02/19/%E6%B8%85%E9%99%A4%E7%84%A1%E4%B8%BB%E5%A5%97%E4%BB%B6%E5%8F%8A%E5%A5%97%E4%BB%B6%E5%AE%89%E8%A3%9D%E6%9A%AB%E5%AD%98%E6%AA%94/


由於在使用 apt-get install 時,會把相依性套件都安裝起來,但是在 apt-get remove 時,並不會把相依套件刪除,所以會留下很多沒有使用的函式庫。

可以使用下列指令刪除:

$ sudo apt-get autoremove

而在下載完套件後,套件安裝檔在安裝完後也不會自行移除。

可以使用下列指令移除:

移除「所有」快取套件暫存安装档:

$ sudo apt-get clean

移除「舊版」快取套件暫存安装档:

$ sudo apt-get autoclean

How to build linux kernel 2.6.26 on Ubuntu 8.04


1. sudo passwd root [Enter] 建立 root 最大權限使用者的密碼

2. su [Enter] 切換成 root

3. Get the late source code of linux from http://www.kernel.org &

Put this file to /home/gary/

4. cd /home/gary/ [Enter]

5.





[轉載]How to build PLAYWND at WINCE5.0 step by step

WINCE5.0中PLAYWND的編譯步驟

PLAYWND源文件的目錄是
$(_PUBLICROOT)\DIRECTX\SDK\SAMPLES \DSHOW\PLAYERS\PLAYWND,
默認情況下WINCE是不會將playwnd加入到內核中去的。

下面介紹的是如何成功編譯playwnd項目及將playwnd.exe加入到wince內核中。

1. 打開PLAYWND目錄下的source文件,
將TARGETTYPE=LIBRARY改為TARGETTYPE=PROGRAM,
通過這個修改就能把該project編譯成playwnd.exe文件,
而不是只編譯聲成playwnd.lib的庫文件。

2. 此時你可以在FileView中將鼠標移動到playwnd的目錄上,
右鍵點擊並選擇Build Current Project,
在Build的過程中可能會出現一些Link的錯誤
(我的是有出現錯誤,當然如果您沒有出現該錯誤就不用繼續看錯誤處理方法了呵),
這是因為該project沒有加入一些庫文件導致,解決方法見第三點。

3. 如2中的方法,右鍵點playwnd,
選擇Setting->Link,在Additional Libraries一欄中增加如下幾個lib文件
(變量的路徑可在PB上Build OS->Open Release Directory的命令行上輸入env來查看,或者直接進wince.bat查看):

$(_PUBLICROOT)\DIRECTX\SDK\LIB\X86\RETAIL\strmiids.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\coredll.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\commctrl.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\ole32.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\oleaut32.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\uuid.lib
$(_PROJECTROOT)\cesysgen\sdk\lib\x86\retail\commdlg.lib

加完Build過之後這些庫路徑也會被填寫到source文件中,
但除非你對source文件非常熟悉,否則不要直接修改該文件,
筆者就是因為直接修改source文件走了不少彎路,
具體不再多說^_^。

4. 加完第3步驟的lib文件,重新Build, 成功之後會在$(_FLATRELEASEDIR)目錄下產生一個PlayWnd.exe文件,這是就是playwnd的可執行程序。下面介紹一下怎麼將該程序加入到WINCE內核中。

5. 在PB左邊的ParameterView中打開Project.bib文件,加入一行:

PlayWnd.exe $(_FLATRELEASEDIR)\PlayWnd.exe NK S

並在Project.dat中增加下面一行:

Directory("\Windows\MYAPP"):-File("PlayWnd.exe","\Windows\PlayWnd.exe")

修改完該配置文件之後
在PB中選擇Build OS->Copy Files To Relsase Directory使配置文件生效,
但此時$(_FLATRELEASEDIR)目錄下的PlayWnd.exe可能已經被刪除,
必須重新Build 一個,然後在PB中選擇Build OS->Make Runtime Image.
這時產生的NK.BIN進入CE之後在\WINDOWS\MYAPP目錄下就有PlayWnd.exe程序。

6. 如果想用DirectShow寫個播放器,PLAYWND可是個好例子哦。。。

Windows CE下驅動開發

要想真正瞭解驅動程序必須結合一些驅動程序源碼,
在此我以串口驅動程序(COM16550)中初始化過程為線索簡單講一講驅動開發的基礎知識。

  Windows CE下的串口驅動程序能夠處理所有I/O行為似串口的設備,
包括基於16450、16550 UART(通用異步收發芯片)
的設備和一些採用DMA的設備,常見的有9針串口、紅外I/O口、Modem等。
在%_WINCEROOT%\Public\Common\OAK\Drivers\Serial目錄下,
COM_MDD2子目錄包含新的串口驅動MDD層函數代碼。
COM16550子目錄包含串口驅動PDD層代碼。
SER16550子目錄包含的一系列函數專用於控制與16550兼容的UART,
這樣PDD層的主要工作就是調用SER16550中的函數。
還有一個ISR16550子目錄包含的是串口驅動程序專用的可安裝ISR(中斷服務例程),
而很多硬件設備驅動程序採用CE默認的可安裝ISR giisr.dll。
一般串口設備相應的註冊表設置例子及意義如下: 鍵 意義
"SysIntr"=dword:13 串口1的中斷ID為十進制13
"IoBase"=dword:02F8 串口1的IO空間首地址為十六進制2F8
"IoLen"=dword:8 串口1的IO空間長度為8個字節
"DeviceArrayIndex"=dword:0 串口1的索引,是1的由來
"Order"=dword:0 串口1驅動的加載順序
"DeviceType"=dword:0 串口1的設備類型
"DevConfig"=hex: 10,00 .... 串口1在與Modem設備通訊時的配置,如波特率、奇偶校檢等 "FriendlyName"="COM1:" 串口1在撥號程序中顯示的名字
"Tsp"="Unimodem.dll" 串口1 被用於與Modem設備通訊的時候要加載的TSP
(TAPI Service provider)DLL
"Prefix"="COM" 串口1的流接口的前綴
"Dll"="com16550.Dll" 串口1的驅動程序DLL   

SysIntr由CE在文件Nkintr.h中預定義,用於唯一標識中斷設備。
OEM可以在文件Oalintr.h中定義自己的SysIntr。

常見的預定義
SysIntr有SYSINTR_NOP(中斷只由ISR處理,IST不再處理),
SYSINTR_RESCHED(重新調度線程),
SYSINTR_DEVICES(由CE預定義的設備中斷ID的基值),
SYSINTR_PROFILE、SYSINTR_TIMING、SYSINTR_FIRMWARE等都是基於SYSINTR_DEVICES定義的。

IoBase是串口1的IO地址空間的首地址,IoLen是IO空間的大小。
IO地址空間只存在於x86平台,如果在其它平台硬件寄存器必須映射到物理地址空間,
那子鍵的名稱為MemBase和MemLen。

在x86平台更多硬件的寄存器由於IO空間的局限也映射到物理地址空間。
DeviceArrayIndex是設備的索引,用於區分同類型的設備。

Prefix是流驅動程序的前綴,當應用程序調用CreateFile函數傳遞COM1:參數時,
文件系統負責與串口驅動程序通信,串口驅動程序是在CE啟動時由device.exe加載的。
  
下面從MDD層函數COM_Init開始探索串口驅動的初始化過程。

COM_Init是在串口設備被檢測後由設備管理器device.exe調用的,
主要的作用是初始化設備,它的唯一參數Identifier是由device.exe傳遞的,
其類型是一個字符串指針,字符串的內容是HLM\Drivers\Active\xx,
xx是一個十進制數(device.exe會跟蹤系統中每個驅動程序,
把加載的驅動程序記錄在Active鍵下)。

COM_Init先分配一個HW_INDEP_INFO結構體,
這個結構體是獨立於串口硬件的頭信息(MDD、PDD、SER16550都包含自己獨特的結構體,
具體的結構體定義請參見串口驅動源碼),分配之後再初始化結構體中每個成員,
初始化結構體後調用
OpenDeviceKey((LPCTSTR)Identifier)打開
HLM\Drivers\Active\xx\Key包含的註冊表路徑,
在這裡路徑一般為HLM\Drivers\BuiltIn\Serial,
即串口的驅動程序信息在註冊表中所處的位置。
COM_Init接著在HLM\Drivers\BuiltIn\Serial
下查詢DeviceArrayIndex、Priority256的值,
Priority256指定了驅動程序的優先級,
如果沒有就用默認的優先級。

接下來調用GetSerialObject(DeviceArrayIndex),
這個函數由PDD層定義,返回HWOBJ結構體,
這個結構體主要包含PDD層和SER16550定義的函數的指針。
也就是說MDD通過調用這個函數才能調用底層實現的函數。
接下來的大多數工作都是調用底層函數實現初始化。
第一個調用的底層函數SerInit主要設置由用戶設置的硬件配置,
例如線路控制、波特率。它調用Ser_GetRegistryData函數得到保存在註冊表中的硬件信息,Ser_GetRegistryData在內部調用系統提供的DDKReg_GetIsrInfoDDK和DDKReg_GetWindowInfo函數得到在HLM\Drivers\BuiltIn\Serial下
保存的IRQ、SysIntr、IsrDll、IsrHandler、IoBase、IoLen。

IRQ是邏輯中斷號,IsrDll表示當前驅動程序的可安裝ISR所在的DLL名稱,
IsrHandler 表示可安裝ISR的函數名稱。
在這裡順便提一下可安裝ISR,
讀者在我以前發表的關於OAL的文章中可以瞭解到OEM在OEMInit函數中關聯IRQ和SysIntr,當硬件設備發生中斷時,ISR會禁止同級和低級中斷,然後根據IRQ返回關聯的SysIntr,
內核根據ISR返回的SysIntr喚醒相應的IST(SysIntr與IST創建的Event關聯),
IST處理中斷之後調用InterruptDone解除中斷禁止。

在OEMInit中關聯的缺點是一旦編譯了CE內核後就無法添加這種關聯了,
而一些硬件設備會隨時插拔或者共享中斷,要關聯這樣的硬件設備解決方法就是可安裝ISR,
可安裝ISR專用於處理指定的硬件設備發出的中斷,
所以如果硬件設備需要可安裝ISR必須在註冊表中添加IsrDll、IsrHandler。

多數硬件設備採用CE默認的可安裝ISR giisr.dll,
格式如下: "IsrDll"="giisr.dll" "IsrHandler"="ISRHandler"   
如果一個硬件驅動程序需要可安裝ISR而開發者又不想自己寫一個,
那麼可以利用giisr.dll來實現。除了在註冊表中添加如上所示外,
還要在驅動程序中調用相關函數註冊可安裝ISR。
偽代碼如下:

g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);
GIISR_INFO Info;
PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};
TransBusAddrToStatic(BusType, dwBusNumber, PortAddress, dwAddrLen, &dwIOSpace, &(PVOID)PhysAddr) Info.SysIntr = dwSysIntr;

Info.CheckPort = TRUE; Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE; Info.UseMaskReg = TRUE;
Info.PortAddr = PhysAddr + 0x0C;
Info.PortSize = sizeof(DWORD);
Info.MaskAddr = PhysAddr + 0x10; KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &Info, sizeof(Info), NULL, 0, NULL);

  LoadIntChainHandler函數負責註冊可安裝ISR,參數1為DLL名稱,
參數2為ISR函數名稱,
參數3為IRQ。
TransBusAddrToStatic函數在後面講。
如果要利用giisr.dll作為可安裝ISR,必須先填充GIISR_INFO結構體,
CheckPort=TRUE表示giisr要檢測指定的寄存器來確定當前發出中斷的是否是這個設備。PortIsIO表示寄存器地址屬於哪個地址空間,
FALSE表示是內定空間,TRUE表示IO空間。
UseMaskReg=TRUE表示設備有一個掩碼寄存器,
專用於指定當前設備是否是中斷源,也就是發出中斷,
而MaskAddr表示掩碼寄存器的地址。如果對Info.Mask賦值,
那麼PortAddr表示一個特殊的寄存器地址,
這個寄存器的值與Mask的值&運算的結果如果為真,
則證明當前設備是中斷源,否則返回SYSINTR_CHAIN
(表示當前ISR沒有處理中斷,內核將調用ISR鏈中下一個ISR),
如果UseMaskReg=TRUE,
那麼MaskReg寄存器的值與PortAddr指定的寄存器的值&運算的結果如果為真,
則證明當前設備是中斷源。   
函數SerInit接著調用函數Ser_InternalMapRegisterAddresses轉換IO地址並且映射地址,Ser_InternalMapRegisterAddresses在
內部調用系統提供的HalTranslateBusAddress(Isa, 0, ioPhysicalBase, &inIoSpace, &ioPhysicalBase)函數將
與總線相關的地址轉換為系統地址,
參數1為總線類型,
參數2為總線號,
參數3為要轉換的地址
(PHYSICAL_ADDRESS類型,實際是LARGE_INTEGER型),
參數4指定寄存器地址屬於IO地址空間還是物理地址空間,
參數5返回轉換後的物理地址。

觀察HalTranslateBusAddress的源碼得知如果是在x86平台,
這個函數除了把參數3賦給了參數5其餘什麼都沒有做,
而非x86平台將inIoSpace的值置為0,表示一定是物理地址。

在調用HalTranslateBusAddress前要確定從註冊表中
得到的寄存器地址到底是屬於哪個地址空間的,
例如:
ULONG inIoSpace = 1; ///1表示是IO空間
PHYSICAL_ADDRESS ioPhysicalBase = {iobase, 0}; ///相當於ioPhysicalBase.LowPart = iobase   

在地址轉換後就要將轉換後的地址映射到驅動程序
(一般IST和應用程序一樣運行在用戶模式)能夠訪問的虛擬地址空間
(0x80000000以下)和ISR能夠訪問的靜態虛擬地址空間中(0x80000000以上)。

例如:
////如果地址屬於物理地址空間
ioPortBase = (PUCHAR)MmMapIoSpace(ioPhysicalBase, Size, FALSE);
TransBusAddrToStatic(Isa, 0, ioPhysicalBase, Size, &inIoSpace, ppStaticAddress);   

MmMapIoSpace函數負責將物理地址映射到驅動程序能夠訪問的虛擬地址空間中,
通過源碼分析MmMapIoSpace在內部分別調用:
pVirtualAddress =VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS); VirtualCopy(pVirtualAddress,
(PVOID)(SourcePhys >> 8),
SourceSize, PAGE_PHYSICAL
PAGE_READWRITE
(CacheEnable ? 0 : PAGE_NOCACHE));   

VirtualAlloc分配一塊和MemLen一樣大小的虛擬地址空間,因為參數1為0,所以內核自動分配。
一般MemLen小於2MB,所以會在應用程序的地址空間中分配。

VirtualCopy負責將硬件設備寄存器的物理地址與VirtualAlloc分配的虛擬地址做一個映射關係,
這樣驅動程序訪問PvirtualAddress實際上就是訪問第一個寄存器。

因為硬件設備寄存器的物理地址一定是在512MB(CE支持RAM的最大值)以上,
所以除了最後的參數要加PAGE_PHYSICAL外,
第二個參數物理地址也要右移8位(或者除以256)。
映射硬件寄存器當然PAGE_NOCACHE是必須加的。

TransBusAddrToStatic函數
負責將物理地址映射到ISR能夠訪問的靜態虛擬地址空間中,當出現中斷共享時,
ISR要負責訪問硬件設備的某一個寄存器來判斷中斷源,所以將寄存器的物理地址映射到靜態虛擬地址空間中是必要的(ISR只能訪問靜態的虛擬地址空間)。

所謂靜態虛擬地址空間是指在OEMAddressTable中定義的虛擬地址空間(當然是0x80000000以上)。

在x86平台一般這個表只定義RAM的物理地址與虛擬地址對應關係,
而硬件設備的寄存器地址並不在該表中定義,
所以如果要創建一塊靜態的虛擬地址空間供ISR訪問,
必須在此之前調用
CreateStaticMapping函數
在0xC4000000到0xE0000000虛擬地址空間中分配。
TransBusAddrToStatic函數
在內部就是調用了CreateStaticMapping函數。

註:硬件設備的寄存器地址也可以在OEMAddressTable中定義。

////如果地址屬於IO空間
ioPortBase = (PUCHAR)ioPhysicalBase.LowPart;
*ppStaticAddress=ioPortBase

這種情況只屬於x86平台,是IO空間就可以直接訪問,即使是用戶模式。   
SerInit函數接著初始化SER_INFO結構體成員,之後調用SL_Init函數,
這個函數在ser16550中定義,負責初始化SER16550_INFO結構體,
在這個結構體中保存串口8個寄存器的地址。
SerInit函數執行完畢後COM_Init函數創建接收緩衝區,
然後調用StartDispatchThread函數初始化中斷並且創建IST。
StartDispatchThread函數在內部調用InterruptInitialize函數關聯SysIntr和Event,
然後調用InterruptDone函數告訴內核當前串口可以中斷處理,
接著調用CreateThread函數創建IST線程。
(over吧,再往下說就和串口硬件有關了,看多了沒註釋的代碼我也煩!!)

Windows CE 作業系統模型圖


Windows CE 簡介

Windows CE為微軟研發的嵌入式作業系統,可以應用在各種嵌入式系統,或是硬體規格層次較低的電腦系統(例如很少的記憶體,較慢的中央處理器等)。微軟並未定義CE縮寫由來,一般解釋則有Customer Embedded、Compact Edition、Consumer Electronics等等。

概覽
Windows CE可以使用在各式各樣的系統上,最有名的是Pocket PC以及
微軟的SmartPhone. 其他較不為人知的裝置包括微軟的車用電腦、
電視機上盒、生產線上的控制設備、公共場所的資訊站等等,
有些裝置甚至沒有任何人機介面。
Windows CE 並非從桌上型電腦的Windows(NT,98,XP...)修改縮小而來,
而是使用一套完全重新設計的核心,所以它可以在功能非常有限的硬體上執行。
雖然核心不同,但是它卻提供了高度的Win32 API軟體開發介面的相容性,
功能有記憶體管理、檔案操作、多執行緒、網路功能等。
因此,開發桌上型電腦軟體的人可以很容易編寫甚或直接移植軟體到Windows CE上。
一個與其他微軟作業系統的差異是 Windows CE 提供原始碼,
首先已經提供了原始碼給部分廠商,讓廠商能夠依照他們自己的硬體架構修改原始碼,
例如:
在 Windows CE 的開發 IDE 軟體 Platform Builder 中就提供了
許多開放原碼的常用軟體元件,
但是一些與硬體架構的軟體元件仍然以二進制檔案形式來提供。
版本
Windows CE 1.0是最早期的版本,非常不穩定,隨便版本不斷的釋出,使得WinCE日趨穩定。
Windows CE 1.0 (Pegasus)
Windows CE 2.0, 2.11, 2.12 (Mercury)
Windows CE 3.0 (Cedar)
Windows CE .NET (4.0, 4.1, 4.2) (Talisker)
Windows CE 5.0 (Macallan)
Windows Embedded CE 6.0 (Yamazaki)

最新功能
目前最新的Windows CE為Windows CE 6.0,這個版本在核心部分有很大的進步:
所有系統元件都由EXE改為DLL,並移到 kernel space.
全新設計的虛擬記憶體架構
全新的裝置驅動程式架構,同時支援 User Mode 與 Kernel Mode 兩種驅動程式。
突破只能執行 32 個工作元(process)的限制,可以執行 32768 個工作元。
每一工作元的的虛擬記憶體限制由32 M 增加到全系統總虛擬記憶體。
Platform Builder IDE 整合到 Microsoft Visual Studio 2005。
新的安全架構,確保只有被信任的軟體可以在系統中執行。
UDF 2.5 檔案系統。
支援 802.11i (WPA2)及 802.11e (QoS) 等無線規格, 及多重 radio support.
支援 x86, ARM, SH4, MIPS 等各種處理器。
提供新的 Cellcore components 使系統在行動電話網路中更容易建立資料連結及啟動通話。
在開發環境上,微軟也提供相容於.NET Framework的開發元件:.NET Compact Framework,讓正在學習.NET或已擁有.NET程式開發技術的開發人員能迅速而順利的在搭載Windows CE .NET系統的裝置上開發應用程式
用於掌上電腦Pocket PC以及智慧手機Smart Phone上的Windows CE系統稱為Windows Mobile,目前的最新版本為Windows Mobile 6.1
限制
Windows CE 只支援 UNICODE,故char必須改為TCHAR, WCHAR。
Windows CE不支援重疊I/O。
WinCE的許多APIs功能都受限,如:CreateThread 函式在許多參數在Windows CE下都不支援,第1、2、5的參數值必須設為NULL或0。 HThread = CreateThread(NULL, 0, Thread, nParameter, 0, &dwThreadID);

Windows CE.net 系統註冊表

限制:

鍵或鍵值項的名字最多為255個字元 , 資料最大4KB , 鍵嵌套層次最多16層




Windows CE.net 註冊表根鍵 :

HKEY_LOCAL_MACHINE -> 硬體及驅動程式配置資料

HKEY_CURRENT_USER -> 使用者配置資料

HKEY_CLASSES_ROOT -> OLE和檔案類型匹配配置資料

HKEY_USERS -> 適用於所有使用者的儲存資料

KernelIoControl [轉載]

參考 msdn http://msdn2.microsoft.com/en-us/library/ms886729.aspx
argument 依序是
CommandConde
InBuffer Pointer
InBuffer Size
OutBuffer Pointer
OutBuffer Size
Buffer Pointer to Save the returned value (DWORD)就和 Linux 的 IOControl 一樣。
但是這個 IOControl 是對 Kernel ,在source code上來說,也就是 OAL。
CE 的 Driver 都是run 在 User Space (6.0以前),
所以driver 的access 方法不一樣。
driver 的iocontrol 和 linux 的比較類似,
就是 open device,然後用iocontrol function。
但是 kernel 不是 driver,所以就不用open 了,
直接呼叫 KernelIoControl( )就可以。
自己要加一些 Kernel IoControl command的話,要
先define IOControl code ,
用 CTL_CODE 宣告,
有很多argument和限制,
參考 http://msdn2.microsoft.com/en-us/library/ms904001.aspx
在oal 中寫好處理的function,
通常會是 OALIoCtlXXX( ),
這個funciton 的argument也是限制的,
要符合iocontrol 的四個argument : in,insize,out,outsize。
在oak_ioctl_tab.h 中建立IOcontrol code和 iocontrol function 的關聯。
在 CTL_CODE的說明頁,
有說明可以指定 cotrol type.(oal 的就是FILE_DEVICE_HAL)。
這樣看來,也可以用 FILE_DEVICE_BATTERY 來指定由battery 來handle ?

Little endian & Big endian是何意思?[轉載]

Endian是什麼意思呢?還是讓我們先來看看下面的情況,
這是記憶體中一個WORD值中的內容,
那麼這個WORD中的值是0x1234呢,還是0x3412 ?

low byte high byte
0x12 0x34

熟悉x86彙編的人立刻就知道這個值應為0x3412,
很對,
但在一些情況下,
比如說你在SGI的機器上看到這種情況,
則正好相反,
0x1234才是正確答案,
這與CPU內部處理資料的方式有關。
這兩種處理方式都存在于不同廠商生產的CPU之中,
在上例中若此WORD值為0x3412的,
我們稱之為little-endian,
若為0x1234的,
我們稱之為big-endian,
這是兩種不同的byte orders。
MSDN中有比較精確的定義如下:

Byte Ordering Byte ordering Meaning
big-endian The most significant byte is on the left end of a word.
little-endian The most significant byte is on the right end of a word.

一般來說我們不用關心byte ordering的問題,
但若要涉及跨平臺之間的通信和資源分享,
則不得不考慮這個問題了。
也許你會說,
我永遠不會去用其他非x86的CPU,
也許是這樣,
你甚至可以不必知道我們最常用的Intel,
AMD等生產的x86的byte ordering是little-endian的,
而且按現在的裝機數量來看,
可以說世界上絕大多數CPU是little-endian的,
但多瞭解一些沒有什麼壞處,
也許有用上的一天,
實際若您要涉及到網路編程,
瞭解一些還是有所幫助的,
看完本文後您就應該知道
為何socket編程中為何要用到如 ntohl, htonl, ntohs, htons
這幾個看起來名字似乎怪怪的API了,
也很容易理解這些函數名的意義了。

假設我們要在不同byte ordering的機器之間傳輸和交換資料,
那該怎麼辦呢,
有兩個方法,
一是全部轉換成文本來傳輸(如XML使用的),
另一個方法兩方都按照某一方的byte order,
這時就涉及到了不同byte order之間相互轉換的問題
(網路傳輸標準如TCP/IP採用第二種方法並且由於歷史的原因,
byte ordering是big-endian的)。
兩種之間該如何轉換呢?
方法有很多,我們可以先看看MFC中在
處理serialize的代碼中所用的方法(List),
雖然代碼應該是高效易讀的,
但我個人並不喜歡它,
原因是我覺得這不是一種通用優美的方法.
下面列出的是我自己寫的轉換的代碼:

template F3D_INLINE T ConvertEndian(T t)
{
T tResult = 0;
for (int I = 0; I < tresult =" (t">>= 8;
}
return t Result;
}

原理非常簡單,
交換位元組順序,
我就不多說了,
當然這個寫法並不是快速的,
只是通用的(我沒條件試, 若有不對之處請指出), 若要快速的代碼,
可以在不同platform上用與platform
相關的代碼, 如在PowerPC上有 "load word byte-reversed indexed" (lwbrx)
和 "load halfword byte-reversed indexed" (lhbrx) 指令,
在x86上還可用BSWAP單個彙編指令等,
在類型上專為int16, int32寫的通用的代碼也可以比這快得多.

當然如果在byte ordering相同的情況下,
應該不必用這個轉換函數,
所以我們可以定義一個宏來處理不同的byte ordering,
也可以在運行時測試byte ordering,
下面的代碼給出了一個簡單的測試方法。

// Test for endianness.
F3D_INLINE bool IsLittleEndian(void)
{
DWORD dwTestValue = 0x12345678L;
return (*((BYTE*)&dwTestValue) == 0x78);
}

但是float比較怪,
有可能所涉及到不僅僅是byte order的問題,
因為有些平臺如Alpha不使用IEEE的浮點格式,
還得自己轉換。
當然同上,
其他的方法一是將所用的float用文本方式輸入輸出,
另一個辦法是在某些情況下可將其轉換成定點數再處理,
這裏我不再深入。

如果是讀寫第三方已經指定byte order的檔或資料流程,
比如說讀SGI的點陣圖檔格式,
則可以直接自行按指定的byte order拼起來,
不必考慮host機是何種byte ordering。
下面我給出相應的代碼:

// Read a little-endian TYPE from address
template F3D_INLINE T GetLittleEndian(const BYTE* pBuf)
{
T tResult = 0;
pBuf += sizeof(T) - 1;
for (int I = 0; I < tresult =" *pBuf" tresult =" 0;" i =" 0;" tresult =" *pBuf" i =" 0;">>= 8;
}
}

// Set a big-endian T on a address
template F3D_INLINE void SetBigEndian(BYTE* pBuf, T t)
{
pBuf += sizeof(T) - 1;
for (int I = 0; I <>>= 8;
}
}

從上文可以看出,byte order挺簡單的,
一般應用中可能也用不上,
但若您對寫跨平臺的程式有興趣,
則一定要瞭解的比較清楚才行。
以上代碼都是從實際使用的源碼中取下來的。

附:常見Processor, OS的byte ordering情況

Processor OS Order
x86 (Intel, AMD, … ) All little-endian
DEC Alpha All little-endian
HP-PA NT little-endian
HP-PA UNIX big-endian
SUN SPARC All? big-endian
MIPS NT little-endian
MIPS UNIX big-endian
PowerPC NT little-endian
PowerPC non-NT big-endian
RS/6000 UNIX big-endian
Motorola m68k All big-endian

[轉載] EVC CString常用方法簡介

引用:http://www.wretch.cc/blog/bigdstut/13523891
CString::Compareint Compare( LPCTSTR lpsz ) const;
返回值 字串一樣 返回0
小於lpsz 返回-1
大於lpsz 返回1
區分大小字元
CString s1( "abc" );
CString s2( "abd" );
ASSERT( s1.Compare( s2 ) == -1 );
ASSERT( s1.Compare( "abe" ) == -1 );

CString::CompareNoCase
int CompareNoCase( LPCTSTR lpsz ) const;
返回值 字串一樣 返回0
小於lpsz 返回-1
大於lpsz 返回1
不區分大小字元

CString::Collate
int Collate( LPCTSTR lpsz ) const;
同CString::Compare

CString::CollateNoCase
int CollateNocase( LPCTSTR lpsz ) const;
同CString::CompareNoCase

CString::CString
CString( );
CString( const CString& stringSrc );
CString( TCHAR ch, int nRepeat = 1 );
CString( LPCTSTR lpch, int nLength );
CString( const unsigned char* psz );
CString( LPCWSTR lpsz );
CString( LPCSTR lpsz );
例子最容易說明問題
CString s1;
CString s2( "cat" );
CString s3 = s2;
CString s4( s2 + " " + s3 );
CString s5( 'x' ); // s5 = "x"
CString s6( 'x', 6 ); // s6 = "xxxxxx"
CString s7((LPCSTR)ID_FILE_NEW); // s7 = "Create a new document"
CString city = "Philadelphia";

CString::Delete
int Delete( int nIndex, int nCount = 1);
返回值是被刪除前的字串的長度
nIndex是第一個被刪除的字元,nCount是一次刪除幾個字元。根據我實驗得出的結果:當nCount>
刪除字串的最大長度(GetCount() - nIndex)時會出錯,當nCount過大,沒有足夠的字元刪除
,此函數不執行。
例子
CString str1,str2,str3;
char a;
str1 = "nihao";
str2 = "nIhao";
int x;
// int i=(str1 == str2);
str1.Delete(2,3);
如果nCount(3) > GetCount() – nIndex (5-2)就會執行錯誤

CString::Empty
Void Empty( );
沒有返回值 清空操作;
例子
CString s( "abc" );
s.Empty();
ASSERT( s.GetLength( ) == 0 );

CString::Find
int Find( TCHAR ch ) const;
int Find( LPCTSTR lpszSub ) const;
int Find( TCHAR ch, int nStart ) const;
int Find( LPCTSTR lpszSub, int nStart ) const;
返回值 不匹配的話返回 -1; 索引以0 開始
nStar 代表以索引值nStart 的字元開始搜索 ,
即為包含以索引nStart字元後的字串
例子
CString s( "abcdef" );
ASSERT( s.Find( 'c' ) == 2 );
ASSERT( s.Find( "de" ) == 3 );
Cstring str(“The stars are aligned”);
Ing n = str.Find('e',5);
ASSERT(n == 12)

CString::FindOneOf
int FindOneOf( LPCTSTR lpszCharSet ) const;
返回值 不匹配的話返回 -1; 索引以0 開始
注意::返回此字串中第一個在lpszCharSet中 也包括字元並且從零開始的索引值
例子
CString s( "abcdef" );
ASSERT( s.FindOneOf( "xd" ) == 3 ); // 'd' is first match.

CString::Format
void Format( LPCTSTR lpszFormat, ... );
void Format( UINT nFormatID, ... );
lpszFormat 一個格式控制字串
nFormatID 字串識別字
例子
CString str;
Str.Format(“%d”,13);
此時Str為13

CString::GetAt
TCHAR GetAt( int nIndex ) const;
返回標號為nIndex的字元,你可以把字串理解為一個陣列,GetAt類似於[].注意nIndex的範
,如果不合適會有調試錯誤。

CString::GetBuffer
LPTSTR GetBuffer( int nMinBufLength );
返回值
一個指向物件的(以空字元結尾的)字元緩衝區的LPTSTR 指標。
參數
nMinBufLength
字元緩衝區的以字元數表示的最小容量。這個值不包括一個結尾的空字元的空間。
說明
此成員函數返回一個指向CString 物件的內部字元緩衝區的指標。返回的LPTSTR 不是const,
此可以允許直接修改CString 的內容。如果你使用由GetBuffer 返回的指標來改變字串的內容,
必須在使用其他的CString 成員函數之前調用ReleaseBuffer 函數。
在調用ReleaseBuffer 之後,由GetBuffer 返回的位址也許就無效了,因為其他的CString 操
可能會導致CString 緩衝區被重新分配。如果你沒有改變此CString 的長度,則緩衝區不會被重
分配。當此CString 物件被銷毀時,其緩衝區記憶體將被自動釋放。
注意,如果你自己知道字串的長度,則你不應該添加結尾的空字元。但是,當你用ReleaseBuffer
釋放該緩衝區時,你必須指定最後的字串長度。如果你添加了結尾的空字元, 你應該給
eleaseBuffer 的長度參數傳遞-1 ,ReleaseBuffer 將對該緩衝區執行strlen 來確定它的長

下面的例子說明了如何用CString::GetBuffer。
// CString::GetBuffer 例子
CString s( "abcd" );
#ifdef _DEBUG
afxDump << "CString s " << p =" s.GetBuffer(" n =" str.Insert(" n ="="" n =" str.Insert(" n ="="" n =" str.Insert(555," n ="="" nnewlength =" -1" s = "abc" p =" s.GetBuffer(" n =" str.Remove(" n ="="" str ="="“This" n =" strZap.Replace('-'," n ="="" strzap ="="" n =" strBang.Replace(" n ="="1" n =" strBang.Replace" n ="="" n =" strBang.Replace(" n ="="" strbang ="="" s ="="" str = "\n\t a" str = "abbcadbabcadb ">

深 入C++Builder 探 訪 動 態 連 結 函 式 庫 (Dynamic Linking Libraries,DLLs)

http://www2.borland.com.tw/tw/td001018.html

[轉載] 如何將vc 的lib包成dll

一.此篇文章的目的為何??
示範如何由 VC 產生一個 Win32 Static Library 及一個 Win32 Dynamic Link Library,
並分別由 BCB 引用二.此篇文章的主題為何??
共分為四大部分,以下將分別針對這四大部分做介紹
===================================================================
1.利用 VC 產生一個 Win32 Static Library (LIB)
1.1.開啟 VC 選擇「File/New」開啟「New」Dialog
1.2.在左邊「Projects」Tab 中選擇「Win32 Static Library」
1.3.在右邊「Project name」欄位填好名稱 (例如: VCLib)
1.4.在右邊「Location」欄位選擇專案要存放的目錄
1.5.然後按「OK」Button,開啟「Win32 Static Library-Step 1 of 1」 Dialog,
確認「Pre-Compiled header」及「MFC support」不要打勾
1.6.然後按「Finish」Button
1.7.在 VC 的 IDE 環境之中,你會發現這個 LIB 專案還是空的,
因此我們要先為這個專案新增 *.h 及 *.cpp
1.8.選擇「File/New」開啟「New」Dialog
1.9.在左邊「Files」Tab 中選擇「C/C++ Header File」
1.10.在右邊確認「Add to project」有打勾,並在「File」欄位輸入檔案名稱 (例如: VCLib.h),
最後按「OK」Button
1.11.在 VC 的 IDE 環境之中,你會發現這個 LIB 專案已經新增了一個檔案 VCLib.h
(在左邊的「FileView」Tab 中的樹狀結構中的「Header Files」
子目錄裡面可以看得到)
1.12.選擇「File/New」開啟「New」Dialog
1.13.在左邊「Files」Tab 中選擇「C++ Source File」
1.14.在右邊確認「Add to project」有打勾,並在「File」欄位輸入檔案名稱
(例如: VCLib.cpp), 最後按「OK」Button
1.15.在 VC 的 IDE 環境之中,你會發現這個 LIB 專案已經新增了一個檔案 VCLib.cpp
(在左邊的「FileView」Tab 中的樹狀結構中的「Source Files」
子目錄裡面可以看得到)
1.16.接著在 VCLib.h 檔案裡面加入以下的程式碼
#ifndef __VCLIB_H__
#define __VCLIB_H__
int AddMethod(int a, int b);
#endif // __VCLIB_H__
1.17.接著在 VCLib.cpp 檔案裡面加入以下的程式碼
#include "VCLib.h"
int AddMethod(int a, int b)
{
return(a+b);
}
1.18.選擇「Build/Rebuild All」就會開始編譯此 LIB 專案直至完成
1.19.若編譯無誤的話,用檔案總管檢視你儲存的專案目錄下,有可能會產生一個「Debug」
子目錄,也有可能產生一個「Release」子目錄,這跟此 LIB 專案的設定有關
(可從「Project/Settings」中去設定要編譯成「Debug」或「Release」版本,
預設值為「Debug」),在此建議先編譯成「Release」版本,
因此會在「Release」子目錄下找到這個 LIB 專案主要的成品檔案「VCLib.lib」
1.20.選擇「File/Close Workspace」關閉此 LIB 專案
====================================================================
2.利用 VC 及 1. 中的 LIB 產生一個 Win32 Dynamic Link Library (DLL)
2.1.開啟 VC 選擇「File/New」開啟「New」Dialog
2.2.在左邊「Projects」Tab 中選擇「Win32 Dynamic-Link Library」
2.3.在右邊「Project name」欄位填好名稱 (例如: VCDll)
2.4.在右邊「Location」欄位選擇專案要存放的目錄
2.5.然後按「OK」Button,開啟「Win32 Dynamic-Lin Library - Step 1 of 1」Dialog,
選擇「A DLL that exports some symbols」(選擇這個的原因,是因為可以偷懶)
2.6.然後按「Finish」Button
2.7.在 VC 的 IDE 環境之中,你會發現這個 DLL 專案已經自動新增了五個檔案
stdAfx.cpp, VCDll.cpp, stdAfx.h, VCDll.h, ReadMe.txt(在左邊的「FileView」
Tab 中的樹狀結構中的「Source Files」及「Header Files」子目錄裡面可以看得到)
2.8.在 VC 的 IDE 環境之中,在左邊的「FileView」
Tab 中選擇「VCDll files」按滑鼠右鍵,
選擇「Add Files to Project」開啟「Insert Files into Project」Dialog,
選擇「檔案類型」為「Library Files (.lib)」,
「檔案名稱」選擇剛剛 1. 中的成品「VCLib.lib」
2.9.如果加入成功的話,在 VC 的 IDE 環境之中,左邊的「FileView」
樹狀結構中可以看得到剛剛加入的檔案「VCLib.lib」
2.10.更改檔案 VCDll.h 的內容如下
#ifndef __VCDLL_H__
#define __VCDLL_H__
#define VCDLL_API __declspec(dllexport)
extern "C" {
VCDLL_API int AddMethodEx(int a, int b);
}
#endif // __VCDLL_H__
2.11.更改檔案 VCDll.cpp 的內容如下
#include "stdafx.h"
#include "VCDll.h"
#include "..\VCLib\VCLib.h"
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int AddMethodEx(int a, int b)
{
return(AddMethod(a, b));
}
2.12.選擇「Build/Rebuild All」就會開始編譯此 DLL 專案直至完成
2.13.若編譯無誤的話,用檔案總管檢視你儲存的專案目錄下,
有可能會產生一個「Debug」子目錄,也有可能產生一個「Release」子目錄,
這跟此 DLL 專案的設定有關 (可從「Project/Settings」中
去設定要編譯成「Debug」或「Release」版本,預設值為「Debug」),
在此建議先編譯成「Release」版本,因此會在「Release」子目錄下找到
這個 DLL 專案主要的成品檔案「VCDll.dll」
2.14.選擇「File/Close Workspace」關閉此 DLL 專案
3.利用 BCB 引用 2. 中的 DLL (靜態連結)
3.1.開啟 BCB 並新增一個 Application 專案
3.2.選擇「File/Save Project As」將此專案更名為「BCBSta」,
並將檔案儲存到自定的目錄之下
3.3.將 VCDll.dll 及 VCDll.h 兩個檔案,複製到 BCBSta 專案的目錄下,
並另外開啟一個 DOS BOX (Command Line),在 BCBSta 專案的目錄 下鍵入指令
「implib -a VCDll.lib VCDll.dll」,如果成功的話,
會在 BCBSta 目錄下產生一個新的檔案「VCDll.lib」
3.4.在 BCB 的 IDE 中選擇「View/Project Manager」開啟「Project Manager」Dialog,
把剛剛產生的檔案「VCDll.lib」加入此 BCBSta 專案
3.5.在 Form1 上拉一個 Button1,然後在 Unit1.cpp 中加入以下的程式碼
#include "VCDll.h"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ShowMessage(IntToStr(AddMethodEx(1, 1)));
}
3.6.執行 BCBSta 專案看看是否成功??
3.7.關閉 BCB
4.利用 BCB 引用 2. 中的 DLL (動態連結)
4.1.開啟 BCB 並新增一個 Application 專案
4.2.選擇「File/Save Project As」將此專案更名為「BCBDyn」,
並將檔 安儲存到自定的目錄之下
4.3.將 VCDll.dll 檔案複製到 BCBDyn 專案的目錄下
4.4.在 Form1 上拉一個 Button1,然後在 Unit1.cpp 中加入以下的程式碼
typedef int (*ADDMETHODEX)(int, int);
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HINSTANCE dll=NULL;
ADDMETHODEX AddMethodEx=NULL;
dll=LoadLibrary("VCDll.dll");
if(dll!=NULL)
{
AddMethodEx=(ADDMETHODEX)GetProcAddress(dll, "AddMethodEx");
if(AddMethodEx!=NULL)
{
ShowMessage(IntToStr(AddMethodEx(1, 1)));
}
FreeLibrary(dll);
}
}
4.5.執行 BCBDyn 專案看看是否成功??
4.6.關閉 BCB三.有完整的範例程式碼可以下載嗎??
http://delphi.ktop.com.tw/loadfile.php?TOPICID=10460160&CC=233940
四.範例程式該如何使用呢?? 下載並解壓縮檔案 VCBCB1.zip 以後,會產生 VCBCB1 目錄,
在此目錄之下又有四個子目錄,
這四個子目錄分別對應到
二. 中所敘述的四個部分五.如果寫得不好,或是有不對的地方,請大家多多指教

[轉載] *.LIB 兩種涵義

    1. 第一種是 Win32 Static Library,這種檔案的格式在 VC 與 BCB 是不相同的,而且用 coff2omf 這個工具也無法正確互轉格式,目前也 還沒有看過能夠正確轉換的工具 (因為無法分別清楚得知 VC/BCB 的 Win32 Static Library 內部的詳細資料結構);你所說的那個檔案 (comsupp.lib)
    2. 另外一種通常是專案型態為 Win32 Dynamic-Link Library 的副屬產出物, 例如: 假設你有一個 DLL 的專案名稱叫做 ABC 的話,在編譯、連結完成之 後,除了可以產生 ABC.dll 之外,也會產生 ABC.lib。當 ABC.dll 要給別 人使用的時候,就要把 ABC.dll/ABC.lib/ABC.h 至少這三個檔案提供給對方 ,這樣子對方就可以選擇靜態連結 (會同時用到 ABC.dll/ABC.lib/ABC.h 這 三個檔案) 或動態連結 (只會用到 ABC.dll/ABC.h 這兩個檔案) 來呼叫你的 ABC.dll 內部的 function

我與HonHon之旅二: 南方澳&頭城之旅

第一次開著我的Honda CV8 到南方澳吃海產 , 真是棒極了 ,
~非常感謝JOE的帶路唷 ~

這間是我ㄇ去吃的海產店唷(富美活海鮮)~還不錯吃唷




以下是我ㄇ去吃的菜色~~~

重點是白蝦真是他媽的好吃ㄚ~~~值得推薦






南方澳有名的南天宮唷~~~


金媽祖附駕



玉媽祖


金媽祖

頭城阿宗芋冰城~~推薦在推薦唷



Terry


Joe

[轉載] DeviceIoControl

DeviceIoControl 的MSDN reference
以 WAVEDEV 為例IO Control Code 定義在 PUBLIC\COMMON\OAK\INC\WAVEDEV.H 中
這個 header file 的 comment 中有說明 audio driver 的複雜架構。
WAVDEV 處理的IO Control Cmd 有
IOCTL_MIX_MESSAGE
IOCTL_WAV_MESSAGE
都定義在這裡,這兩個 command code 都屬於 FILE_DEVICE_SOUND (分別是 3, 115)。
device io control 又把parameter 作進一步擴充,
把argument 再定義為 message (PMMDRV_MESSAGE_PARMS):

typedef struct {
UINT uDeviceId;
UINT uMsg;
DWORD dwUser;
DWORD dwParam1;
DWORD dwParam2;
} MMDRV_MESSAGE_PARAMS;
所以.. WAVEDEV 的IO Control handler 再依照 uMsg 細分 command。
使用時,要先CreateFile("drivername"..),
"drivername"就是那個 3 char + 1 index.
取得的handle 傳入 DevIoControl ( )作第一個argument,
prototype:
BOOL DeviceIoControl( HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
和 KernelIoControl( )比起來,除了一開始的 hDevice外,
就是最後的 Overlapped. - 這個固定要用 NULL。

How to build bluetooth driver for wince 5.0 (CSR)

Step1 : 在 "\Platform\專案名稱\Files\Platform.reg 加入以下敘述
;Setting ANW / CSR Bluetooth; @CESYSGEN IF BTD_CSR
[HKEY_LOCAL_MACHINE\Software\Microsoft\Bluetooth\HCI]
"flags"=dword:1 "name"="COM1:" "baud"=dword:1c200
[HKEY_LOCAL_MACHINE\Software\Microsoft\Bluetooth\sys]

"COD"=dword:200408
[HKEY_LOCAL_MACHINE\ExtModems\Bluetooth_dun]

"port"="COM8:"
"DeviceType"=dword:1
"FriendlyName"="Bluetooth DUN on COM8"
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial1]
"DeviceArrayIndex"=dword:0
"Irq"=dword:1c
"MemBase"=dword:50000000 ; 設定 2440 Uart0 Memory Address
"MemLen"=dword:2C
"InterruptBitsShift"=dword:0 ; UART 0 Interrupt Sub Register shift bit.
"ISTTimeouts"=dword:200 ; every 512 ticks checking Modem status.

"Prefix"="COM"
"Index"=dword:1
"Dll"="serial_smdk2440.dll"
"Order"=dword:0
"Priority"=dword:0
"Port"="COM1:"
"DeviceType"=dword:0
"FriendlyName"=LOC_DISPLAYNAME_COM1
"Tsp"="unimodem.dll"
"IClass"="{CC5195AC-BA49-48a0-BE17-DF6D1B0173DD}"
"DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00
"opened"=dword:0
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Step2 : 加入Profile組件(Catalog)
Bluetooth DUN Gateway
BlueHS/HF and Audio Gateway Service
Bluetooth LAP and Configuration Utility
Bluetooth PAN
Bluetooth Stack with Integrated CSR Chipset Driver
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Step3 : Set C:\WINCE500\PBWorkspaces\Focus_B01_64x64\
WINCE500\Focus_B01_64x64_ARMV4I\OAK\MISC

if /i not "%1"=="pass3" goto :Not_Pass3
set CE_MODULES=%CE_MODULES% bthcsr
goto :EOF
:Not_Pass3
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Step4 : copy files to release folder & makeimg

爛到爆

土城國泰世華聯合中心的蔡課長,服務態度極差ㄉ

有空我再說說他ㄇㄉ惡行惡狀

台科大我來啦

台灣科技大學資工所我來啦 !!!

訂車拉

終於在這ㄍ月訂下HONDA CIVIC 1.8 EX-स
雖然有點貴,不過卻是一台好車,期待4月底的交車日 ^^

虹光大成就-密教灌頂(一)