整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          126A打印提示系統不支持請求的命令 解決方案3

          126A打印提示系統不支持請求的命令 解決方案3

          近許多小伙伴都升級了Windows10最新的更新補丁KB5006670,但是這會引起打印機無法連接共享打印機甚至出錯的問題。但是卸載更新又顯示無法卸載,那么遇到這種情況我們要怎么解決呢?

          注意,這個如果你是小白,應用時務必小心,備份好相關數據避免出現災難性故障,如果你是專業人員請自行確認下面方法的合理性。


          操作方法:
          用管理員權限運行CMD, 然后在命令提示符中輸入以下命令看是否可以卸載KB5006670。

          wusa /uninstall /KB:5006670

          如果還是無法卸載,建議在安全模式下進行卸載。

          因為此補丁是針對Win10 2004以上版本推出的最新更新,如果還是無法卸載,我懷疑可能在更新的時候存在文件損壞,運行“sfc /scannow”命令嘗試修復系統文件,重置 Windows 更新組件。

          手動重置 Windows 更新組件

          打開 Windows 命令提示符。 若要打開命令提示符,請單擊 “開始” 》 “運行”。 復制并粘貼(或鍵入)以下命令,然后按 Enter:

          cmd

          停止 BITS 服務、Windows 更新服務 和 加密服務。 為此,請在命令提示符下鍵入以下命令。 在鍵入每條命令后按 Enter。

          net stop bits

          net stop wuauserv

          net stop cryptsvc

          刪除 qmgr*.dat 文件。 為此,請在命令提示符下鍵入以下命令,然后按 Enter:

          Del “%ALLUSERSPROFILE%\Application Data\Microsoft\Network\Downloader\qmgr*.dat”

          如果這是使用本文中的步驟解決 Windows 更新問題的首次嘗試,請轉到步驟 5,而無需執行步驟 4 中的步驟。 如果在執行除步驟 4 以外的所有步驟后仍無法解決 Windows 更新問題,則只能在此時在故障排除中執行步驟 4 中的步驟。 步驟 4 中的步驟也由上述“修復解決方案”的“攻擊性”模式執行。

          將以下文件夾重命名為 *.BAK:

          %Systemroot%\SoftwareDistribution\DataStore

          %Systemroot%\SoftwareDistribution\Download

          %Systemroot%\System32\catroot2

          為此,請在命令提示符處鍵入以下命令。 在鍵入每條命令后按 Enter。

          Ren %Systemroot%\SoftwareDistribution\DataStore DataStore.bak

          Ren %Systemroot%\SoftwareDistribution\Download Download.bak

          Ren %Systemroot%\System32\catroot2 catroot2.bak

          將 BITS 服務 和 Windows 更新服務 重置為默認安全描述符。 為此,請在命令提示符下鍵入以下命令。 在鍵入每條命令后按 Enter。

          sc.exe sdset bits D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)

          sc.exe sdset wuauserv D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)

          在命令提示符下鍵入以下命令,然后按 Enter:

          cd /d %windir%\system32

          重新注冊 BITS 文件和 Windows 更新 文件。 為此,請在命令提示符下鍵入以下命令。 在鍵入每條命令后按 Enter。

          regsvr32.exe atl.dll

          regsvr32.exe urlmon.dll

          regsvr32.exe mshtml.dll

          regsvr32.exe shdocvw.dll

          regsvr32.exe browseui.dll

          regsvr32.exe jscript.dll

          regsvr32.exe vbscript.dll

          regsvr32.exe scrrun.dll

          regsvr32.exe msxml.dll

          regsvr32.exe msxml3.dll

          regsvr32.exe msxml6.dll

          regsvr32.exe actxprxy.dll

          regsvr32.exe softpub.dll

          regsvr32.exe wintrust.dll

          regsvr32.exe dssenh.dll

          regsvr32.exe rsaenh.dll

          regsvr32.exe gpkcsp.dll

          regsvr32.exe sccbase.dll

          regsvr32.exe slbcsp.dll

          regsvr32.exe cryptdlg.dll

          regsvr32.exe oleaut32.dll

          regsvr32.exe ole32.dll

          regsvr32.exe shell32.dll

          regsvr32.exe initpki.dll

          regsvr32.exe wuapi.dll

          regsvr32.exe wuaueng.dll

          regsvr32.exe wuaueng1.dll

          regsvr32.exe wucltui.dll

          regsvr32.exe wups.dll

          regsvr32.exe wups2.dll

          regsvr32.exe wuweb.dll

          regsvr32.exe qmgr.dll

          regsvr32.exe qmgrprxy.dll

          regsvr32.exe wucltux.dll

          regsvr32.exe muweb.dll

          regsvr32.exe wuwebv.dll

          重置 Winsock。 為此,請在命令提示符下鍵入以下命令,然后按 Enter:

          netsh winsock reset

          如果運行的是 Windows XP 或 Windows Server 2003,必須設置代理設置。 為此,請在命令提示符下鍵入以下命令,然后按 Enter:

          proxycfg.exe -d

          重啟 BITS 服務、Windows 更新服務 和 加密服務。 為此,請在命令提示符下鍵入以下命令。 在鍵入每條命令后按 Enter。

          net start bits

          net start wuauserv

          net start cryptsvc

          如果正在運行 Windows Vista 或 Windows Server 2008,請清除 BITS 隊列。 為此,請在命令提示符下鍵入以下命令,然后按 Enter:

          bitsadmin.exe /reset /allusers

          當然我想如果有還原點,系統還原到安裝KB之前的狀態也可以。

          其它辦法:

          1. 使用命令提示符卸載更新: - 打開命令提示符(以管理員身份運行)。 - 輸入命令:wusa /uninstall /kb:5006670 - 按下回車鍵執行命令。 - 等待卸載完成,重啟電腦。

          2. 使用Windows更新目錄卸載更新: - 打開文件資源管理器,導航到以下路徑:C:\Windows\SoftwareDistribution\Download - 刪除該文件夾中的所有內容。 - 打開設置應用程序,選擇“更新和安全”。 - 點擊“檢查更新”按鈕,讓系統重新下載更新文件。 - 安裝新的更新文件,重啟電腦。

          在前面

          • 嗯,學習Ansible高級特性,整理這部分筆記
          • 博文內容涉及 復雜Ansible劇本的編寫規范一個具體的編寫Demo
          • 食用方式: 理論有些枯燥,不感興趣小伙伴可以直接跳過去看Demo需要有ansible基礎,了解ansible自定義角色

          「 人們一思索,上帝就發笑 ---猶太諺語」


          如何編寫清晰的Ansible腳本

          對于運維小伙伴來講,Ansible并不陌生,配置簡單,上手容易,只要掌握幾個基本的模塊就可以解決好多運維中重復的事,但是對于處理更為高級的功能和更大、更復雜的項目時,管理和維護Ansible Playbook或高效使用將變得更加困難。

          下面的的playbook是一個k8s安裝環境初始化的劇本,其實現方式簡單,是在k8s集群中所有節點都需要做的一些處理,實現如下功能

          • 配置firewallselinux,配置hosts
          • 關閉swap
          • 配置yum
          • 安裝docker-ce,導入缺少的鏡像,配置docker加速
          • 安裝k8s相關包:kubelet、kubeadm、kubectl
          • 啟動kubelet服務
          - name: init k8s
            hosts: all
            tasks:
              # 關閉防火墻
              - shell: firewall-cmd --set-default-zone=trusted
              # 關閉selinux
              - shell: getenforce
                register: out
              - debug: msg="{{out}}"
              - shell: setenforce 0
                when: out.stdout !="Disabled"
              - replace:
                  path: /etc/selinux/config
                  regexp: "SELINUX=enforcing"
                  replace: "SELINUX=disabled"
              - shell: cat /etc/selinux/config
                register: out
              - debug: msg="{{out}}"
              - copy:
                  src: ./hosts
                  dest: /etc/hosts
                  force: yes
             # 關閉交換分區
              - shell: swapoff -a
              - shell: sed -i '/swap/d' /etc/fstab
              - shell: cat /etc/fstab
                register: out
              - debug: msg="{{out}}"
              # 配置yum源
              - shell: tar -cvf /etc/yum.tar /etc/yum.repos.d/
              - shell: rm -rf /etc/yum.repos.d/*
              - shell: wget ftp://ftp.rhce.cc/k8s/* -P  /etc/yum.repos.d/
              # 安裝docker-ce
              - yum:
                  name: docker-ce
                  state: present
              # 配置docker加速
              - shell: mkdir /etc/docker
              - copy:
                  src: ./daemon.json
                  dest: /etc/docker/daemon.json
              - shell: systemctl daemon-reload
              - shell: systemctl restart docker
              # 配置屬性,安裝k8s相關包
              - copy:
                  src: ./k8s.conf
                  dest: /etc/sysctl.d/k8s.conf
              - shell: yum install -y kubelet-1.21.1-0 kubeadm-1.21.1-0 kubectl-1.21.1-0 --disableexcludes=kubernetes
              # 缺少鏡像導入
              - copy:
                  src: ./coredns-1.21.tar
                  dest: /root/coredns-1.21.tar
              - shell: docker load -i /root/coredns-1.21.tar
              # 啟動服務
              - shell: systemctl restart kubelet
              - shell: systemctl enable kubelet
          

          如果搭建的集群節點很多,那么使用ansible要方便很多,但是上面的劇本沒有使用角色,所有的操作都耦合在一起,所以看起來不是特別清晰,可讀性差,而且一些可變的變量也沒有抽離出來。復用性差,也沒有考慮失敗回滾的問題,大部分的操作是通過shell模塊來完成的,尤其是對一些文件的操作,shell模塊不滿足冪等性。

          高效的使用Ansible不僅僅在于功能或工具的使用,對于實踐方法和項目組織更重要,對于劇本的編寫規范,有以下三點:

          • 保持簡單
          • 井然有序
          • 經常測試

          保持簡單

          Ansible 的一大優勢是簡潔性。使用playbook保持簡單,我們就能更加輕松地使用、修改和理解它們。

          保持 Playbook 的可讀性

          • 確保playbook有恰當注釋且易于閱讀。合理地使用垂直空白和注釋。
          • 始終為play和任務提供有意義的名稱,明確play或任務的用途。
          • 對于劇本編寫文件格式,YAML 它非常適合表述?系列的字典和數組。
          • 對于難以在Ansible Playbook 中表述?些復雜的控制結構或條件,可以通過模板Jinja2過濾器巧妙地處理變量中的數據。
          • 使用原生 YAML 語法,而不是“折疊”的語法,以下示例不是推薦的格式:
          - hosts: node1,node2
            tasks:
              - yum: name=httpd state=present
              - copy: content="RHCE Test" dest=/var/www/html/index.html force=yes
              - service: name=httpd state=restarted enabled=yes
              - service: name=firewalld state=restarted enabled=yes
              - firewalld: service=http state=enabled permanent=yes immediate=yes
          

          使用現有的模塊

          • 編寫新playbook時,從基礎playbook開始,并盡可能使用靜態清單
          • 在構建設計時,將debug 模塊用作測試或存根。
          • playbook按預期工作后,使用importincludeplaybook分成較小的邏輯組件。
          • 盡量使用Ansible中包含的特殊用途模塊,而不是command、shell、raw這樣的通用模塊。使用為特定任務設計的模塊可以輕松地使 Playbook 具有冪等性,且易于維護。

          遵循標準樣式

          編寫Ansible項目時,應考慮和同時遵循標準的樣式:遵循統一的標準有助于提高可維護性和可讀性。

          • 縮進多少個空格
          • 如何使用垂直空白
          • 如何命名任務劇本角色和變量
          • 應對什么進行注釋
          • 如何注釋

          井然有序

          Ansible項目的組織和Playbook的運行方式有助于維護、故障排除和審計

          遵循變量命名約定

          因為 Ansible 具有相對扁平的命令空間,所以變量名非常重要。應使用描述性變量且應闡明內容,如 apache_tls_port ,在角色中給最好能給角色變量添加前綴,如myapp_apache_tls_port

          標準化項目結構

          在文件系統上構建 Ansible 項目時,請使用統一的模式,推薦的示例:

          在這里插入圖片描述

          Playbook 結構的一大優勢在于,可以將較?的playbook分成較小的?件,使其更易閱讀,而較小的子playbook 可能會包含可以獨立運行的、適合特定用途的 play

          使用動態清單

          動態清單支持從?個真實的中央來源集中管理主機和組,并確保清單自動更新。動態清單一般與云提供商、容器和虛擬機管理系統結合使用。

          如果無法使用動態清單,則其它工具可以動態構建組或其他信息。group_by 模塊根據事實動態生成組成員資格,該組成員資格對 playbook 的其余部分有效。

          # Create nested groups
          - group_by:
              key: el{{ ansible_distribution_major_version }}-{{ ansible_architecture }}
              parents:
                - el{{ ansible_distribution_major_version }}
          
          TASK [group_by] ****************************************************************************************************
          task path: /root/ansible/group_by.yaml:5
          [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
          changed: [192.168.26.82]=> {
              "add_group": "el7-x86_64",
              "changed": true,
              "parent_groups": [
                  "el7"
              ]
          }
          changed: [192.168.26.81]=> {
              "add_group": "el7-x86_64",
              "changed": true,
              "parent_groups": [
                  "el7"
              ]
          }
          

          充分利用組

          主機可以是多個組的成員,可以按以下特征將主機劃分不同的種類:

          • 地理位置
          • 環境
          • 站點或服務

          將角色用于可重復使用的內容

          • 角色可以是 playbook 保持簡單,能夠通過重復利用項目間的通用代碼來減少工作量。
          • 通過變量使角色成為可配置的通同角色,以便在將它們用于?組不同的playbook時無需對其進行編輯。
          • 使用ansible-galaxy init命令來初始化角色的目錄結構。
          • RHEL 中的redhat-system-roles 軟件提供的角色受到官方支持。
          • 也可以通過Ansible Galaxy 提供的角色,但是注意其質量和安全。
          • 將角色保存在項目的roles子目錄中。

          集中運行 Playbook

          使用一個專用的控制節點來控制對系統的訪問和審計 Ansible 活動,讓所有的 Ansible Playbook 都從上面運行。

          系統管理員仍應在系統上擁有自己的賬戶,以及用于連接受管主機的憑據,并在需要時可以進行權限提升。當系統管理員離職時,因從受管主機的authorized_keys文件中刪除其 SSH 密鑰,同時撤銷其 sudo 權限。也可以考慮使用紅帽 Ansible Tower 作為中央控制節點。

          經常測試

          在開發過程中、任務運行時以及Playbook投入使用后,應經常測試 Playbook 和 task

          測試任務的結果

          如果需要確認任務是否成功,請驗證任務的結果,而不要信任模塊的返回代碼

          - start web server 
            service: 
              name: httpd 
              status: started
          - name: Check web site from web server 
            uri: 
              ur1: http://{{ ansible_fqdn}}
              return_content: yes 
            register: example_webpage 
            failed_when: example_webpage. status !=200
          

          使用 Block/Rescue 來恢復或回滾

          block 指令可用于對任務進行分組,與 rescue 指令結合使用時,可幫助從錯誤和故障中恢復。

          ---
          - name: block test
            hosts: node1
            tasks:
              - block:
                  - debug: msg="vg myvg not found"   #提示卷組沒找到
                  - debug: msg="create vg myvg .. .."   #做其他操作(比如創建這個卷組...)
                when: ('myvg' not in ansible_lvm.vgs)   #當卷組myvg不存在時
                rescue:
                  - debug: msg="creating failed .. .."     #block失敗時提示創建卷組失敗
                always:
                  - shell: vgscan          #列出卷組信息
                    register: list         #保存到名為list的變量
                  - debug: msg={{list.stdout_lines}}     #提示卷組掃描結果
          
          

          使用最新的 Ansible 版本開發 Playbook

          即使不在?產中使用最新版本的 Ansible,也應該定期針對 Ansible 的最新版本測試 playbook。這將避免在Ansible 模塊和功能不斷演變時出現的問題。

          如果 playbook 在運行時顯示警告或棄用消息,應注意它們并做出相應的調整。通常,Ansible 中的某?功能已棄用或有變化,則該項目會在刪除或更改功能之前提早四個小版本提供棄用通知。

          使用測試工具

          使用 ansible-playbook --syntax-check 命令進行語法檢測

          ┌──[root@vms81.liruilongs.github.io]-[~/ansible]
          └─$ansible-playbook group_by.yaml --syntax-check
          
          playbook: group_by.yaml
          ┌──[root@vms81.liruilongs.github.io]-[~/ansible]
          └─$echo 22 >> group_by.yaml
          ┌──[root@vms81.liruilongs.github.io]-[~/ansible]
          └─$ansible-playbook group_by.yaml --syntax-check
          ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
          JSON: No JSON object could be decoded
          
          Syntax Error while loading YAML.
            could not find expected ':'
          
          The error appears to be in '/root/ansible/group_by.yaml': line 11, column 1, but may
          be elsewhere in the file depending on the exact syntax problem.
          
          The offending line appears to be:
          
          
          22
          ^ here
          

          使用 ansible-playbook --check 命令,檢查模式,針對check_mode中的實際受管主機運行 Playbook(不會改變主機狀態),以查看Playbook執行的更改。此項檢查不能保證完全準確性,因為 playbook 可能需要實際運行?些任務,playbook 中的后續任務才能正常運行。可能有?些標記有check_mode: no指令的任務。這些任務即使在檢查模式中也會運行。

          tasks:
            - name: This task will always make changes to the system
              ansible.builtin.command: /something/to/run --even-in-check-mode
              check_mode: no
          
            - name: This task will never make changes to the system
              ansible.builtin.lineinfile:
                line: "important config"
                dest: /path/to/myconfig.conf
                state: present
              check_mode: yes
              register: changes_to_important_config
          

          一個Demo

          下面我們來看一個完整的Demo,這個Demo做的事很簡單,但是劇本編寫清晰,在三臺機器部署一個web服務,其中一臺機器用haproxy作為負載,剩下的兩臺機器提供web能力(安裝http服務并部署APP),劇本中創建了四個角色,用于描述四種行為:

          • 安裝配置負載均衡器
          • 安裝配置web服務器
          • 部署服務到web服務器
          • LB、HTTP 服務的firewall配置

          配置、清單、主劇本文件編寫

          編寫一個ansible.cfg 配置文件,這個不多講,指定主機清單文件位置和ssh用戶,配置sudo 提權方式。

          [defaults]
          inventory=inventory
          remote_user=devops
          
          [privilege_escalation]
          become=True
          become_method=sudo
          become_user=root
          become_ask_pass=False
          

          inventory 主機清單文件,定義兩個分組,

          • 作為LB的機器為 servera
          • 提供web能力的機器為serverb和serverc
          [lb_servers]
          servera.lab.example.com
          
          [web_servers]
          server[b:c].lab.example.com
          

          site.yml為定義的實際執行的主劇本,這里通過,這里通過import_playbook模塊來引入一個外部的調用角色的模塊。一般情況下,當一個playbook很長很復雜,可以通過對劇本進行拆分。通過模塊化的方式將多個playbook組合為一個完整的playbook,或者把文件中的任務列表插入到play中.

          嗯,簡單介紹下,ansible 可以使用兩種方式實現劇本的模塊化:

          • 包含內容:動態操作(include_task),在playbook運行期間,Ansible會在內容到達時處理包含的內容
          • 導入內容: 靜態包含(import_task,import_playbook),在playbook運行之前,Ansible在最初解析的時候預處理導入的內容

          和Java web體系中的Jsp腳本有些類似,通過include指令和include動作引入文件

          我們可以看到,site.yml執行的三個劇本都是通過導入的方式。

          - name: Deploy HAProxy
            import_playbook: deploy_haproxy.yml
          
          - name: Deploy Web Server
            import_playbook: deploy_apache.yml
          
          - name: Deploy Web App
            import_playbook: deploy_webapp.yml
          

          執行順序為,創建LB、創建web Serve,部署 web app,這里把劇本行為抽象為角色,然后在deploy_*里面調用角色,實現了行為和劇本的解耦。

          調用角色劇本編寫

          看一下導入的執行角色的劇本deploy_haproxy.yml

          - name: Ensure HAProxy is deployed
            hosts: lb_servers
            force_handlers: True
          
            roles:
              # The "haproxy" role has a dependency
              # on the "firewall" role. The
              # "firewall" role requires a
              # "firewall_rules" variable be defined.
              - role: haproxy
                firewall_rules:
                  # Allow 80/tcp connections
                  - port: 80/tcp
          

          通過劇本執行LB角色,并且定義·變量firewall_rules,聲明開放的端口協議,這里有一個force_handlers,我們看一下,劇本中handlers用于任務處理(布雷),可以設置一個或一塊任務,但是他不會主動執行,需要通過notify通知觸發(引爆),還有一些需要注意的點:

          • 每個劇本中handlers任務只會執行一次,即使收到多個任務的觸發通知
          • handlers組的每一個任務都要設置名稱(name)
          • handlers的層次與tasks平級
          • 其他任務在必要時,使用notify語句通知handlers任務名
          • 僅當發起notify的任務的執行狀態為changed時,handlers任務才會被執行

          看一個Demo

          ---
          - name: handlers test
            hosts: node5
            tasks:
                - lvol: lv=vo001 size=100M vg=search   #創建邏輯卷vo001
                notify: mkfs     #如果changed則通知格式化(否則無需格式化)
            handlers:
              - name: mkfs     #定義格式化操作處理
                filesystem: dev=/dev/search/vo001 fstype=xfs force=yes 
          ...
          

          那么這里的force_handlers即強制執行的意思,當觸發他的通知對應的任務執行失敗,但是handlers任然會執行,

          deploy_apache.yml

          - name: Ensure Apache is deployed
            hosts: web_servers
            force_handlers: True
          
            roles:
              # The "apache" role has a dependency
              # on the "firewall" role. The
              # "firewall" role requires a
              # "firewall_rules" variable be defined.
              - role: apache
                firewall_rules:
                  # Allow http requests from any
                  # internal zone source.
                  - zone: internal
                    service: http
          
                  # Add servera, the load balancer,
                  # to the internal zone.
                  - zone: internal
                    source: "172.25.250.10"
          

          deploy_webapp.yml

          - name: Ensure Web App is deployed
            hosts: web_servers
            vars:
              - webapp_version: v1.0
          
            roles:
              - role: webapp
          

          這里需要說明下,vars定義的變量屬于劇本變量,而在roles下面的變量為角色變量

          自定義角色編寫

          我們來看一下角色,一共有四個角色,其中三個在上面的deplay_*.yaml 文件中被調用,firewall角色apache和haproxy依賴調用

          • apache http web服務器部署
          • firewall 防火墻部署配置
          • haproxy LB部署配置
          • wen app 能力部署
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles]
          └─$ls
          apache  firewall  haproxy  webapp
          

          關于角色這里我們簡單的回顧下

          ansible 中的role指的是,為了方便復雜任務(包含大批量任務操作、模板、變量等資源)的重復使用,降低playbook劇本編寫難度,而預先定義好的一套目錄結構。

          針對每一個角色,ansible會到固定的目錄去調取特定的數據,關于角色在劇本中的使用,可以看看上面 deplay_*.yaml

          角色內一般不指定hosts: 清單主機列表,而是交給調用此角色的劇本來指定,當然測試除外,具體看下

          haproxy 角色

          haproxy 角色 在劇本中負責LB 相關行為,簡單看一下目錄結構

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles]
          └─$cd haproxy/ #角色根目錄
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$tree
          .
          ├── defaults      #定義變量的缺省值,優先級較低
          │   └── main.yml  
          ├── handlers      #定義handlers處理任務
          │   └── main.yml  
          ├── meta          #定義作者、版本、兼容性、依賴項等描述信息
          │   └── main.yml  
          ├── tasks         #任務入口,最主要的文件
          │   └── main.yml  
          ├── templates     #存放模板文件
          │   └── haproxy.cfg.j2  
          └── tests  # 用于角色測試
              ├── inventory
              └── test.yml
          
          6 directories, 7 files
          

          當然,這里的角色目錄并不是最全的,正常的角色中還會有vars目錄用于定義變量,相對于defaults優先級更高,files目錄存放一些靜態文件,README.md文件用于描述自述信息,我們通過init命令生成一個角色看一下目錄

          ┌──[root@vms81.liruilongs.github.io]-[~/ansible/roles]
          └─$ansible-galaxy init demo
          - Role demo was created successfully
          ┌──[root@vms81.liruilongs.github.io]-[~/ansible/roles]
          └─$ls
          demo
          ┌──[root@vms81.liruilongs.github.io]-[~/ansible/roles]
          └─$tree
          .
          └── demo
              ├── defaults
              │   └── main.yml
              ├── files
              ├── handlers
              │   └── main.yml
              ├── meta
              │   └── main.yml
              ├── README.md
              ├── tasks
              │   └── main.yml
              ├── templates
              ├── tests
              │   ├── inventory
              │   └── test.yml
              └── vars
                  └── main.yml
          
          9 directories, 8 files
          ┌──[root@vms81.liruilongs.github.io]-[~/ansible/roles]
          └─$
          

          嗯,回到我們的haproxy來看一下 defaults目錄下的yaml文件用于定義一些缺省的變量。

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat defaults/main.yml
          # Log-level for HAProxy logs
          log_level: info
          
          # Port exposed to clients
          port: 80
          
          # Name for the default backend
          backend_name: app
          
          # Port backend is exposed to
          backend_port: 80
          
          # The appservers variable is a list
          # of backend servers that provide
          # the web service that is proxied
          # haproxy.  Each server must define:
          # name, address, port. Below is
          # and example structure:
          # appservers:
          #   - name: serverb.lab.example.com
          #     ip_address: 1.2.3.4
          #     port: 5000
          #   - name: serverc.lab.example.com
          #     ip_address: 1.2.3.5
          #     port: 5000
          # The default is no defined backend servers.
          appservers: []
          
          # Socket used to communicate with haproxy service. DO NOT CHANGE
          socket: /var/run/haproxy.sock
          

          handlers這個目錄用于定義需要處理被激活的任務。這里定義了兩個任務,都用到了Service模塊

          • 重新啟動haproxy服務
          • 重新加載haproxy服務配置文件
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat handlers/main.yml
          ---
          # handlers file for haproxy
          
          - name: restart haproxy
            service:
              name: haproxy
              state: restarted
          
          - name: reload haproxy
            service:
              name: haproxy
              state: reloaded
          

          看下meth元數據,作者信息,版本,以及通過dependencies我們可以看到該角色依賴角色firewall

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat meta/main.yml
          galaxy_info:
            author: Ophelia Dunham
            description: A role to ensure deployment of HAProxy
            company: Example, Inc.
          。。。。
            license: license (GPLv2, CC-BY, etc)
          
            min_ansible_version: 2.4
          。。。。
            galaxy_tags: []
          。。
          dependencies:
            - name: firewall
          
          

          這里我們簡單聊聊角色依賴,角色依賴可以在使用角色時自動拉入其他角色。Ansible 執行角色依賴項,則必須使用關鍵字dependenciesmate文件夾下的main.yaml中聲明在指定角色之前插入的角色和參數列表,我們這里的參數是定義在deploy_*.yaml

          「主任務劇本」

          • 通過yum模塊下載負載均衡工具haproxy和反向代理工具socat
          • 通過Service模塊啟動haproxy,并設置開啟自啟
          • 通過template模塊,利用jieja2 模板,替換配置文件,這里處理完要通知前面重載配置文件的handlers
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat tasks/main.yml
          ---
          # tasks file for haproxy
          - name: Ensure haproxy packages are present
            yum:
              name:
                - haproxy
                - socat
              state: present
          
          - name: Ensure haproxy is started and enabled
            service:
              name: haproxy
              state: started
              enabled: yes
          
          - name: Ensure haproxy configuration is set
            template:
              src: haproxy.cfg.j2
              dest: /etc/haproxy/haproxy.cfg
              #validate: haproxy -f %s -c -q
            notify: reload haproxy
          

          模板文件編寫,這里用到了jieja2模板引擎,在一般的python web項目中用的比較多一點,這里簡單的理解為變量替換。

          haproxy.cfg.j2模板里用到了我們之前定義的大量變量,包括default目錄的下main.yaml中定義的變量,以及appservers.yaml中的變量。

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat templates/haproxy.cfg.j2
          #---------------------------------------------------------------------
          # Global settings
          #---------------------------------------------------------------------
          global
              #Send events/messages to rsyslog server.
              log         127.0.0.1:514 local0 {{ log_level }}
          
              chroot      /var/lib/haproxy
              pidfile     /var/run/haproxy.pid
              maxconn     4000
              user        haproxy
              group       haproxy
              daemon
          
             #state changes due to API calls are stored in this file.
             server-state-file /usr/local/haproxy/haproxy.state
          
              # turn on stats unix socket
              #  required for the ansible haproxy module.
              stats socket {{ socket }} level admin
          
              # utilize system-wide crypto-policies
              ssl-default-bind-ciphers PROFILE=SYSTEM
              ssl-default-server-ciphers PROFILE=SYSTEM
          
          #---------------------------------------------------------------------
          # common defaults that all the 'listen' and 'backend' sections will
          # use if not designated in their block
          #---------------------------------------------------------------------
          defaults
              mode                        http
              log                         global
              option                      httplog
              option                      dontlognull
              option http-server-close
              option forwardfor           except 127.0.0.0/8
              option                      redispatch
              retries                     3
              timeout http-request        10s
              timeout queue               1m
              timeout connect             10s
              timeout client              1m
              timeout server              1m
              timeout http-keep-alive     10s
              timeout check               10s
              maxconn                     3000
          
              #Loads state changes from the state file.
              load-server-state-from-file global
          
          #---------------------------------------------------------------------
          # main frontend which proxys to the backends
          #---------------------------------------------------------------------
          frontend main
              mode http
              bind *:{{ port }}
              default_backend {{ backend_name }}
          
          #---------------------------------------------------------------------
          # round robin balancing between the various backends
          #---------------------------------------------------------------------
          backend {{ backend_name }}
              balance roundrobin
          {% for server in appservers %}
              server {{ server.name }} {{ server.ip }}:{{ backend_port }}
          {% endfor %}
          
          

          appservers 清單變量用于定義需要負載的機器域名和ip。這里為了角色的復用性,單獨分離出來。

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices]
          └─$cat appservers.yml
          
          appservers:
            - name: serverb.lab.example.com
              ip: "172.25.250.11"
            - name: serverc.lab.example.com
              ip: "172.25.250.12"
          
          

          剩下的就是測試相關的yaml文件,不多介紹,remote_user指定連接受管機的遠程用戶名

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat tests/inventory
          localhost
          
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/haproxy]
          └─$cat tests/test.yml
          ---
          - hosts: localhost
            remote_user: root
            roles:
              - haproxy
          

          apache 角色

          apache 角色用于提供http 服務,目錄結構相對簡單

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles]
          └─$cd apache/
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/apache]
          └─$tree
          .
          ├── meta
          │   └── main.yml
          ├── tasks
          │   └── main.yml
          └── tests
              ├── inventory
              └── test.yml
          
          3 directories, 4 files
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/apache]
          └─$
          

          meta 文件夾我們這里不多介紹了,涉及防火墻操作,所以依賴firewall角色,看一下主任務劇本

          • yum模塊安裝 http相關包
          • seboolean模塊用于設置selinux開機自啟,允許httpd_can_network_connect 訪問網絡
          • service模塊用于啟動http服務
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/apache]
          └─$cat tasks/main.yml
          ---
          # tasks file for apache
          
          - name: Install http
            yum:
              name:
                - httpd
                - php
                - git
                - php-mysqlnd
              state: present
          
          - name: Configure SELinux to allow httpd to connect to remote database
            seboolean:
              name: httpd_can_network_connect_db
              state: true
              persistent: yes
          
          - name: http service state
            service:
              name: httpd
              state: started
              enabled: yes
          
          

          webapp 角色

          webapp角色用于部署web 項目到httpd服務,主要涉及缺省變量編寫和主任務劇本。

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles]
          └─$cd webapp/
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/webapp]
          └─$tree
          .
          ├── defaults
          │   └── main.yml
          ├── meta
          │   └── main.yml
          ├── tasks
          │   └── main.yml
          └── tests
              ├── inventory
              └── test.yml
          
          4 directories, 5 files
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/webapp]
          └─$
          

          defaults目錄下的清單變量只有一個webapp_message,meta目錄下的元數據不多介紹

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/webapp]
          └─$cat defaults/main.yml
          webapp_message: "This is"
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/webapp]
          └─$cat meta/main.yml
          

          主任務劇本中,用了一個dufault目錄下的缺省變量和一個ansible的魔法變量,一個使用角色時定義的劇本變量。通過copy模塊向http服務的引導頁寫入一句話。

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/webapp]
          └─$cat tasks/main.yml
          ---
          # tasks file for webapp
          
          #- name: Copy the code from the repository
          #  git:
          #    repo: "{{ webapp_repo }}"
          #    version: "{{ webapp_version }}"
          #    dest: /var/www/html/
          #    accept_hostkey: yes
          ##    key_file: deployment key??
          
          - name: Copy a stub file.
            copy:
              content: "{{ webapp_message }} {{ ansible_hostname }}. (version {{ webapp_version}})\n"
              dest: /var/www/html/index.html
          

          最后來看一下firewall角色

          firewall 角色

          firewall 角色并沒有被顯示的調用,那么它是如何被調用的?

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles]
          └─$cd firewall/
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/firewall]
          └─$tree
          .
          ├── defaults
          │   └── main.yml
          ├── handlers
          │   └── main.yml
          ├── meta
          │   └── main.yml
          ├── tasks
          │   └── main.yml
          └── tests
              ├── inventory
              └── test.yml
          
          5 directories, 6 files
          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/firewall]
          └─$
          

          這里就要講到角色依賴,我們上面的haproxy角色apache角色都在meta/main.yaml 文件中依賴了firewall角色,所以haproxy角色apache角色在執行的時候要先執行firewall角色.

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/firewall]
          └─$cat defaults/main.yml
          ---
          # defaults file for firewall
          
          
          # This role requires that firewall_rules variable
          # be defined. The variable is a list of rules, and
          # each rule defines:
          #
          #   service: (optional)
          #   port:    (optional)
          #   zone:    (optional)
          #   source:  (optional)
          #
          # A rule should only define a service or a port.
          # And example definition is:
          #
          # firewall_rules:
          #   - service: http
          #     zone: internal
          #   - port: 8443
          #     source: 192.168.0.2
          
          # By default, no rules are implemented.
          firewall_rules: []
          

          一個重載firewall 配置文件的任務

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/firewall]
          └─$cat handlers/main.yml
          ---
          # handlers file for firewall
          
          - name: reload firewalld
            service:
              name: firewalld
              state: reloaded
          

          主任務文件,編寫防火墻配置,在配置完通知上面的handlers

          ┌──[root@workstation.lab.example.com]-[/home/student/DO447/labs/development-practices/roles/firewall]
          └─$cat tasks/main.yml
          ---
          # tasks file for firewall
          
          - name: Ensure Firewall Sources Configuration
            firewalld:
              source: "{{ item.source if item.source is defined else omit }}"
              zone: "{{ item.zone if item.zone is defined else omit }}"
              permanent: yes
              state: "{{ item.state | default('enabled') }}"
              service: "{{ item.service if item.service is defined else omit }}"
              immediate: true
              port: "{{ item.port if item.port is defined else omit }}"
            loop: "{{ firewall_rules }}"
            notify: reload firewalld
          

          對劇本的clean

          當我們不需要這套環境了需要編寫一個卸載當前環境的劇本clean.yml

          - name: Clean Load Balancers
            hosts: lb_servers
            gather_facts: no
            tasks:
              - name: Remove packages
                yum:
                  name: haproxy
                  state: absent
              - set_fact:
                  firewall_rules:
                    - port: 80/tcp
          
          - name: Clean Web Servers
            hosts: web_servers
            gather_facts: no
            tasks:
              - name: Remove packages
                yum:
                  name: httpd
                  state: absent
              - set_fact:
                  firewall_rules:
                    - zone: internal
                      service: http
                    - zone: internal
                      source: 172.25.250.10
          
          
          
          - name: Clean Firewall rules
            hosts: lb_servers, web_servers
            tasks:
              - name: Ensure Firewall Sources Configuration
                firewalld:
                  source: "{{ item.source if item.source is defined else omit }}"
                  zone: "{{ item.zone if item.zone is defined else omit }}"
                  permanent: yes
                  state: 'disabled'
                  service: "{{ item.service if item.service is defined else omit }}"
                  port: "{{ item.port if item.port is defined else omit }}"
                loop: "{{ firewall_rules }}"
          
              - name: reload firewalld
                service:
                  name: firewalld
                  state: reloaded
          
          - name: Remove web application
            hosts: web_servers
            tasks:
              - name: Remove stub file
                file:
                  state: absent
                  path: "/var/www/html/index.html"
          
          

          下面是Demo完整的結構

          FC控件:

          Windows標準控件:

          windows標準控件由Windows 操作系統提供,在Windows 95中還提供了一些新增的控件。所有這些控件對象都是可編程的,我們可以使用Visual C++提供的對話框編輯器把它們添加到對話框中。Microsoft基礎類庫(MFC)提供了封裝這些控件的類,它們列于表6.1。

          在MFC 中,類CWnd是所有窗口類的基類,很自然的,它也是所控件類的基類。

          Windows標準控件在以下環境下提供:

          windows 95

          Windows NT 3.51及以后版本

          win32s 1.3

          注意:visual C++4.2及以后版本不再支持Win32s.

          MFC基本常用控件基本用法

          VC++控件工具箱:

          按鈕(Button)

          用來接收用戶的命令,應用程序在接收到用戶命令后,通常需要進行一些后臺工作。按鈕可以響應單擊或雙擊動作,在按鈕接收到鼠標動作后,向其父窗口發送相應的控件通知,用戶可以對這些控件通知進行消息映射,從而進行相應的處理。

          在一個對話框中,可以定義一個默認按鈕,這只要選中按鈕屬性中的“Default”選項。如果在對話框活動的時候按下了Enter鍵,則等同于單擊了默認按鈕。MFC提供了CButton類支持按鈕控件。

          復選框(Check Box)

          用來顯示某種可能的選擇,該項選擇是獨立的,用戶可以選中或取消該選項。在選項被選中的時候核選標記出現,選項被取消時核選標記消失。MFC中由CButton類對核選框進行支持,用戶可以通過SetCheck()函數和GetCheck()函數設置或獲取核選框當前的狀態

          BST_UNCHECKED==((CButton*)GetDlgItem(IDC_CHECK_RES1))->GetCheck()
          ((CButton*)GetDlgItem(IDC_CHECK_RES1))->SetCheck(true);		

          編輯框(Edit Control)

          用來接收用戶輸入的字符串通過選擇編輯框的選項,編輯框可以接收字符串、數字、密碼等;編輯框還可以設置成接收多行字符串的模式;可以自動進行大小寫轉換。編輯框可能向父窗口發送多種控件通知,如果用戶需要,可以對這些控件通知進行處理。MFC提供了CEdit類支持編輯框控件

          GetDlgItem(IDC_***)->SetWindowText(Cstring);
           
          GetDlgItem(IDC_***)->GetWindowText(Cstring);

          組合框(Combo Box)

          列表框和編輯框的組合,用戶除了可以在列表中對已經存在的選項進行選擇外,還可以輸入新的選擇。MFC提供了CComboBox類對組合框控件進行支持。

          CComboBox * AAA=(CComboBox*)(GetDlgItem(IDC_***));
           
          AAA->AddString(_T("***"));
           
          AAA->SelectString(0, _T("***"));
           
          AAA->SetCurSel(0);
           
           
          int nSel=AAA->GetCurSel();
           
          AAA->GetLBText(nSel, Cstring);
           
          if(strType.Trim()==_T("***"))

          列表框(List Box)

          用來選擇一系列的可能選擇,用戶通過滾動條可以在這些選擇中瀏覽。在列表框中,可以進行單項選擇,也可以進行多項選擇,這取決于用戶在控件屬性對話框中的設置。MFC提供了CListBox類對列表框控件進行支持。

          組成框(Group Box)

          用來包圍具有邏輯關系的一組控件,在這些控件的周圍加上邊界和標題。需注意的是,組成框僅僅是在視覺效果上對控件進行“成組”,真正的“成組”工作還需要另外一些工作。僅僅在視覺上展現出一組的邏輯關系,并不添加任何代碼

          單選按鈕(Radio Button)

          用來選擇某種可能的選擇,與 (Check Box)復選框不同,該選項不是獨立的

          一般是幾個單選按鈕組成一組同組中的單選按鈕僅有一個按鈕被選中

          MFC同樣使用CButton類對單選按鈕控件進行支持

          SetCheck()函數和GetCheck()函數對單選按鈕也是適用的。

          靜態文本(Static Text)

          用來在指定的位置顯示特定的字符串一般用來標識附近另一個控件的內容。顯示在靜態文本控件中的字符串一般不再改變,但是在需要的時候,必須為其指定一個不同食物ID號,通過調用相應的函數來進行設置。MFC提供了CStatic類支持靜態控件

          圖形控件(Picture Control)

          顯示位圖(Bitmap)和圖標(Icon),圖形繪制與顯示,主要是其方形的區域適合顯示,同樣方形區域也可利用(Static Text)靜態文本框。

          滾動條(Scroll Bar)

          這包括水平滾動條和垂直滾動條,除了在視覺效果上的方向不同外,水平滾動條在被滾動時發生WM_HSCROLL消息,而垂直滾動條在被滾動時發送WM_VSCROLL消息MFC提供了CScrollBar進行支持

          滑塊控件(Slider Control)

          通常用來在程序中接受一系列離散的數值

          用戶可以設置滑塊控件的取值范圍,并可以為控件加上刻度標記以顯示特定位置的含義。

          MFC提供了CSliderCtrl類進行支持

          微調按鈕(Spin Button)

          包括一對緊靠在一起的上下箭頭,使用微調按鈕可以增大或者縮小某個特定的數值。

          微調按鈕往往都需要一個“伙伴”控件,這通常都是一個編輯框

          當微調按鈕的向上箭頭被單擊時,編輯框中的數字就增大;反之則減小MFC提供了CPinButtonCtrl類進行支持

          進度條(Progress Control)

          進行一項需要較長時間的操作時來反應當前的進度

          當操作的進度不斷前進時,進度條就用特色顏色填充進度條框。用戶可以設定進度條的范圍和當前位置。

          MFC提供了CProgressCtrl類進行支持

          CProgressCtrl* progressbar=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS_1);
           
          progressbar->SetRange(0, 4);
           
          progressbar->SetPos(0);

          熱鍵控制(Hot Key)

          熱鍵控件看起來就像一個編輯框,但是在熱鍵控件中能夠立刻反應用戶剛剛按下的鍵組合,這在設置程序的熱鍵時特別有用。

          熱鍵控件只是在“視覺”上顯示了按鍵組合,設置熱鍵的工作還需要用戶添加代碼完成。

          MFC提供了CHotKey類進行支持

          列表控制(List Control)

          按一定的排列順序顯示一系列帶圖標的字符串。

          列表控件提供了四種顯示模式:大圖標(Icon)、小圖標(Small Icon)、列表(List)和報表(Report)

          用戶可以向列表控件中添加新的項,也可以控制列表控件的顯示模式。

          MFC提供了CListCtrl類進行支持

          初始化:

           struct INFO { int id; CString time; CString type; }info; CString id; int nRow=0; id.Format(_T("%d"), info.id); m_ListCtrl.InsertItem(nRow,id); m_ListCtrl.SetItemText(nRow, 1, info.time); m_ListCtrl.SetItemText(nRow, 2, info.type); nRow ++;


          添加記錄:

           
          struct INFO
           
          {
           
          int id;
           
          CString time;
           
          CString type;
           
          }info;
           
          CString id;
           
          int nRow=0;
           
          id.Format(_T("%d"), info.id);
           
          m_ListCtrl.InsertItem(nRow,id);
           
          m_ListCtrl.SetItemText(nRow, 1, info.time);
           
          m_ListCtrl.SetItemText(nRow, 2, info.type);
           
          nRow ++;

          樹形控件(Tree Control)

          顯示一系列項目的層次關系最典型的例子是顯示磁盤上的文件與文件夾

          如果有子項目的話,單擊樹形控件中的項目可以展開或者收縮其子項目

          MFC提供了CTreeCtrl類進行支持

          初始化

             void CConfigDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: 在此處添加消息處理程序代碼  CRect rcWnd; GetClientRect(&rcWnd);  CRect rcChild=rcWnd; rcChild.top=rcWnd.top+10; rcChild.bottom -=10; rcChild.left +=160; rcChild.right -=10; CRect laneRect=rcChild;  if(::IsWindow(m_1Dlg)) m_1Dlg.MoveWindow(rcChild);  if(::IsWindow(m_2Dlg)) m_2Dlg.MoveWindow(rcChild);   if ( ::IsWindow( pTree.GetSafeHwnd() ) ) { pTree.MoveWindow(rcWnd.left+10,rcWnd.top+30,130,350,1); } }

          樹節點切換

             void CConfigDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView=reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知處理程序代碼 HTREEITEM hSelected=pNMTreeView->itemNew.hItem; if(hSelected!=NULL) { pTree.SelectItem(hSelected); int nDat=pTree.GetItemData(hSelected);  switch(nDat) { case 1: /*MessageBox(_T("YNAME"));*/ if(m_pPreWnd) m_pPreWnd->ShowWindow(SW_HIDE);  m_1Dlg.ShowWindow(SW_SHOW); m_pPreWnd=&m_1Dlg; break; case 3: /*MessageBox(_T("XNAME"));*/ if(m_pPreWnd) m_pPreWnd->ShowWindow(SW_HIDE);  m_2Dlg.ShowWindow(SW_SHOW); m_pPreWnd=&m_2Dlg; break;  default: break; } } *pResult=0; }

          改變位置

             void CConfigDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: 在此處添加消息處理程序代碼  CRect rcWnd; GetClientRect(&rcWnd);  CRect rcChild=rcWnd; rcChild.top=rcWnd.top+10; rcChild.bottom -=10; rcChild.left +=160; rcChild.right -=10; CRect laneRect=rcChild;  if(::IsWindow(m_1Dlg)) m_1Dlg.MoveWindow(rcChild);  if(::IsWindow(m_2Dlg)) m_2Dlg.MoveWindow(rcChild);   if ( ::IsWindow( pTree.GetSafeHwnd() ) ) { pTree.MoveWindow(rcWnd.left+10,rcWnd.top+30,130,350,1); } }

          屬性表控件(Tab Control)

          包含大量的控件,可以滿足用戶顯示或者獲取大量數據分類顯示的要求,典型例子是Windows任務欄每個程序標簽。

          每個屬性表又分為好幾個屬性頁,這些屬性頁由各自的標簽進行區分,這些屬性頁中都可以包容其他控件

          在顯示屬性表的時候,一次只能夠顯示一個屬性頁的全部內容,同時顯示其他屬性頁的標簽,用戶通過單擊標簽打開相應的屬性頁。

          MFC提供了CTabCtrl類進行支持

          初始化綁定變量

          m_tab_Light.DeleteAllItems();
           
          m_LightParkingDlg.DestroyWindow();
           
          m_LightStatusDlg.DestroyWindow();
           
          m_tab_Light.InsertItem(0, _T("0001")); // 插入第一個標簽
           
          m_tab_Light.InsertItem(1, _T("0002")); // 插入第二個標簽
           
           
          CRect tabRect; // 標簽控件客戶區的位置和大小
           
          m_tab_Light.GetClientRect(&tabRect); // 獲取標簽控件客戶區Rect
           
          // 調整tabRect,使其覆蓋范圍適合放置標簽頁
           
          tabRect.left +=2;
           
          tabRect.right -=1;
           
          tabRect.top +=21;
           
          tabRect.bottom -=2;
           
          m_LightParkingDlg.Create(IDD_DIALOG_LIGHT_PARKING, &m_tab_Light); // 創建第一個標簽頁
           
          m_LightStatusDlg.Create(IDD_DIALOG_LIGHT_STATUS, &m_tab_Light); // 創建第二個標簽頁
           
          //m_LightParkingDlg.InitData();
           
          m_LightParkingDlg.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(),SWP_SHOWWINDOW);

          控件頁面切換

           CRect tabRect; // 標簽控件客戶區的位置和大小
           
          m_tab_Light.GetClientRect(&tabRect); // 獲取標簽控件客戶區Rect
           
          // 調整tabRect,使其覆蓋范圍適合放置標簽頁
           
          tabRect.left +=2;
           
          tabRect.right -=1;
           
          tabRect.top +=21;
           
          tabRect.bottom -=2;
           
          switch (m_tab_Light.GetCurSel())
           
          {
           
           
          case 0:
           
          m_LightStatusDlg.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
           
          m_LightParkingDlg.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
           
          break;
           
          case 1:
           
          m_LightParkingDlg.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
           
          m_LightStatusDlg.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
           
          break;
           
           
          }

          動畫控件(Animation):

          用來播放一段AVI格式的視頻剪輯。用戶可以控制視頻剪輯的播放、停止和定位,但也僅限于這些功能。動畫控件設置不能播放音頻剪輯,如果用戶需要更高層次的視頻或者音頻的支持,請選用MCIWnd控件

          MFC提供了CAnimateCtrl類對動畫控件進行支持

          高級編輯框(Rich Edit)

          編輯控件(Edit Control)功能的擴展。在高級編輯框中,除了簡單的輸入和編輯字符串外,用戶還可以為字符或段落指定特定的格式,用戶甚至還可以向高級編輯框中插入OLE項

          高級編輯框基本上實現了一個帶格式的文本編輯器功能,而只需要用戶添加少量的接口。

          MFC提供了CRichEditCtrl類進行支持

          日期/時間選擇器(Date Time Picker)

          向用戶提供了一種直觀的選擇日期和時間的方法、日期/時間選擇器在外觀上類似于一個組合框,但是當用戶單擊下拉箭頭時就會展開一個日歷控件供用戶選擇,而一旦用戶做出了選擇,日期/時間選擇器會自動顯示新的日期/時間。MFC提供了CDateTimeCtrl類進行支持。

          SYSTEMTIME times_1; //開始時間日期
           
          SYSTEMTIME timee_1; //結束時間日期
           
           
          CDateTimeCtrl* dtPickctrs_1=(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER_START1); //獲取時間控件句柄
           
          CDateTimeCtrl* dtPickctre_1=(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER_END1);
           
           
          memset(×_1,0,sizeof(times_1)); //時鐘初始化
           
          memset(&timee_1,0,sizeof(timee_1));
           
           
          dtPickctrs_1->GetTime(×_1); //獲取控件所選時間,保存至變量
           
          dtPickctre_1->GetTime(&timee_1);
           
           
           
          CString strTimeStart; //將時間轉換為字符串
           
          strTimeStart.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"), times_1.wYear,times_1.wMonth,times_1.wDay,times_2.wHour,times_2.wMinute,times_2.wSecond);
           
          CString strTimeEnd;
           
          strTimeEnd.Format(_T("%04d-%02d-%02d %02d:%02d:%02d"), timee_1.wYear,timee_1.wMonth,timee_1.wDay,timee_2.wHour,timee_2.wMinute,timee_2.wSecond);
           


          獲取系統時間

          SYSTEMTIME time;
           
          ::GetLocalTime(&time);

          日歷控件(Month Calender)

          如下圖,看似與真正的日歷類似,操作也類似,直觀的為用戶提供了觀察和顯示當前日期的途徑。MFC提供了CMonthCalCtrl類進行支持

          IP地址控件(IP Adress)

          IP地址控件用來輸入和編輯IP地址MFC提供了CIPAddressCtrl類進行支持

          該控件外觀類似于一個編輯框,但是可以自動對輸入的字符按3個一組進行區分和加間隔圓點。IP地址控件為開發支持Internet技術的程序提供了方便。

          擴展組合框(Extended Combo Box)

          在普通組合框(Combo Box)的基礎上還支持圖像列表

          可以在組合框中顯示特定的圖標表示相應的選擇,而不僅僅是顯示文本。

          MFC提供了CComboBoxEx類進行支持

          用戶自定義控件(Custom Control)

          控件使用的時候,它的Class必須有一個類的支持這個窗口類可以VC的類,例如:Button、Edit.在頭文件增加一個CEdit類的成員變量:CEdit m_Text(即點擊右鍵添加變量),然后按照Edit控件使用即可。


          超鏈接控件(SysLink Control ):

          1.用于在 MFC 應用程序上添加超鏈接,就像html中的超鏈接一樣。你點下可以鏈接到一個網頁上去。拖控件到頁面上,并綁定一個變量(m_linkCtrl),里面的內容全部是按照標準的html中href的用法寫的。寫錯了自然鏈接不了的。

          可以去瞧下html里面的href屬性是怎/么設置的.另外要注意的是字符串中雙引號的處理(記得加個轉義符\),添加單擊響應消息

          m_linkCtrl.SetWindowTextW(_T("<a href=\"http://blog.csdn.net/miko_xiaoming\">Miko's Note</a>"));
           
          PNMLINK pNMLink=(PNMLINK) pNMHDR;
           
          ShellExecuteW(NULL, L"open", pNMLink->item.szUrl, NULL, NULL, SW_SHOWNORMAL); //在瀏覽器中打開

          2.同按鈕(Button)控件一樣,響應相應的消息


          多按鈕組合控件(Split Button Control )

          如下圖,實現多選按鈕選擇功能,使用時添加相應菜單


          網絡IP地址輸入輸出控件(Network Address Control):

          可以直接作為inet_addr(ip)的輸入,分隔符為逗號(,)

          指令按鈕控件(command button control)

          不僅可以為按鈕添加相應命令還可以對命令做出注解

          所有控件的公共屬性:

          ID:控件的資源標識。

          Visiable:控件是否可見。

          Disabled:控件是否被禁止、被禁止的控件無法接受鍵盤和鼠標輸入。

          Group:是否從這個空間開始一個新組。

          Tab stop:在程序中是否可以用【Tab】鍵切換到這個控件。

          Help ID:是否給控件分配一個幫助標識,幫助標識基于控件本身的資源標識。

          Client edge:給控件增加一個凹陷的邊界,使整個控件看起來像是凹下去的一樣。

          Static edge:給控件增加一個邊界。

          Modal frame:給控件增加一個3維的框架,與Client edge相反,它是凸出來的。

          Transparent:擁有此屬性的窗口是透明的,它下面的窗口不會被它遮掩住。

          Accept files:擁有此屬性的窗口可以接收拖放文件,如果一個文件被拖動到這個控件上面,控件會收到WM_DROPFILES消息。

          No parent notify:表示控件不向其父窗口發送WM_PARENTNOTIFY消息。

          Right aligned text:表示文本右對齊。

          以上屬性可通過控件的屬性對話框進行設置,在屬性對話框中按【F1】鍵可以查看屬性的幫助信息。

          每一種控件都由一個MFC控件類來管理,當通過資源編輯器在對話框上添加一個控件時,visualC++會自動為控件類生成一個實例,即對象,并調用構造函數,當對話框關閉時,其各個子控件對象被自動銷毀。

          也可以不使用資源編輯器,自己在程序中寫代碼創建、顯示控件并設置控件的屬性。

          所有的控件類都來自CWnd,控件的某些操作和屬性設置需要用到CWnd本身的成員函數,CWnd某些函數經常用來操縱控件和設置控件屬性。

          SetWindowText:設置控件上要顯示的標題文本,即用來設置控件的caption屬性

          GetWindowText:得到控件的標題文本

          EnableWindow:設置控件的Disabled屬性,即社會自控件是否可以接收鍵盤和鼠標的輸入

          SetWindowPos:改變窗口的大小、位置和Z軸次序。

          MoveWindow:改變窗口的大小和位置

          GetWindowRec:得到窗口的大小、位置(信息存放在一個矩形結構中)。

          GetClientRect:得到窗口客戶區的大小(信息存放在一個矩形結構中 )

          ShowWindow:設置窗口的可見性(即窗口是否可見)

          SetWindowText/GetWindowText還可以用來設置/得到對話框的標題文本。

          福利來啦~

          學習從來不是一個人的事情,要有個相互監督的伙伴,對于C/C++感興趣可以關注小編在后臺私信我:【編程交流】一起來學習哦!可以領取一些C/C++的項目學習視頻資料哦!


          主站蜘蛛池模板: 久久久久女教师免费一区| 中文字幕久久久久一区| 色综合视频一区中文字幕| 亚洲日本一区二区三区在线| 亚洲免费视频一区二区三区| 怡红院一区二区在线观看| 国产精品538一区二区在线| 91一区二区视频| 无码人妻一区二区三区精品视频 | 少妇激情一区二区三区视频 | 天码av无码一区二区三区四区| 99久久精品国产免看国产一区| 无码日韩精品一区二区人妻| 国产日韩精品一区二区在线观看| 亚洲欧美日韩中文字幕在线一区| 久久精品亚洲一区二区| 国产免费一区二区三区不卡| 香蕉免费看一区二区三区| 中文字幕一区二区三区免费视频| 久久国产精品免费一区| 国产精品视频一区二区三区无码| 国产自产V一区二区三区C| 少妇激情av一区二区| 亚洲AV无码国产精品永久一区| 亚洲国产精品无码第一区二区三区 | 一区二区三区在线免费| 老鸭窝毛片一区二区三区| 国产一区二区三区精品视频| 高清一区二区三区日本久| 国产美女一区二区三区| 欧美一区内射最近更新| 日韩精品一区二区三区中文字幕| 精品国产亚洲一区二区在线观看 | 激情内射亚州一区二区三区爱妻| 韩日午夜在线资源一区二区| 色婷婷综合久久久久中文一区二区| 精品人妻AV一区二区三区| 精品一区中文字幕| 日产亚洲一区二区三区| 国产精品亚洲一区二区三区久久| 亚洲一区无码中文字幕|