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 如何運作