近許多小伙伴都升級了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 Playbook或高效使用將變得更加困難。
下面的的playbook是一個k8s安裝環境初始化的劇本,其實現方式簡單,是在k8s集群中所有節點都需要做的一些處理,實現如下功能
- 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保持簡單,我們就能更加輕松地使用、修改和理解它們。
- 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
編寫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"
]
}
主機可以是多個組的成員,可以按以下特征將主機劃分不同的種類:
使用一個專用的控制節點來控制對系統的訪問和審計 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 指令結合使用時,可幫助從錯誤和故障中恢復。
---
- 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,也應該定期針對 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做的事很簡單,但是劇本編寫清晰,在三臺機器部署一個web服務,其中一臺機器用haproxy作為負載,剩下的兩臺機器提供web能力(安裝http服務并部署APP),劇本中創建了四個角色,用于描述四種行為:
編寫一個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_servers]
servera.lab.example.com
[web_servers]
server[b:c].lab.example.com
site.yml為定義的實際執行的主劇本,這里通過,這里通過import_playbook模塊來引入一個外部的調用角色的模塊。一般情況下,當一個playbook很長很復雜,可以通過對劇本進行拆分。通過模塊化的方式將多個playbook組合為一個完整的playbook,或者把文件中的任務列表插入到play中.
嗯,簡單介紹下,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通知觸發(引爆),還有一些需要注意的點:
看一個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依賴調用
┌──[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 角色 在劇本中負責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模塊
┌──[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 執行角色依賴項,則必須使用關鍵字dependencies在mate文件夾下的main.yaml中聲明在指定角色之前插入的角色和參數列表,我們這里的參數是定義在deploy_*.yaml
「主任務劇本」
┌──[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 角色用于提供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角色,看一下主任務劇本
┌──[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角色用于部署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 角色并沒有被顯示的調用,那么它是如何被調用的?
┌──[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.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完整的結構
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.
VC++控件工具箱:
用來接收用戶的命令,應用程序在接收到用戶命令后,通常需要進行一些后臺工作。按鈕可以響應單擊或雙擊動作,在按鈕接收到鼠標動作后,向其父窗口發送相應的控件通知,用戶可以對這些控件通知進行消息映射,從而進行相應的處理。
在一個對話框中,可以定義一個默認按鈕,這只要選中按鈕屬性中的“Default”選項。如果在對話框活動的時候按下了Enter鍵,則等同于單擊了默認按鈕。MFC提供了CButton類支持按鈕控件。
用來顯示某種可能的選擇,該項選擇是獨立的,用戶可以選中或取消該選項。在選項被選中的時候核選標記出現,選項被取消時核選標記消失。MFC中由CButton類對核選框進行支持,用戶可以通過SetCheck()函數和GetCheck()函數設置或獲取核選框當前的狀態。
BST_UNCHECKED==((CButton*)GetDlgItem(IDC_CHECK_RES1))->GetCheck()
((CButton*)GetDlgItem(IDC_CHECK_RES1))->SetCheck(true);
用來接收用戶輸入的字符串。通過選擇編輯框的選項,編輯框可以接收字符串、數字、密碼等;編輯框還可以設置成接收多行字符串的模式;可以自動進行大小寫轉換。編輯框可能向父窗口發送多種控件通知,如果用戶需要,可以對這些控件通知進行處理。MFC提供了CEdit類支持編輯框控件。
GetDlgItem(IDC_***)->SetWindowText(Cstring);
GetDlgItem(IDC_***)->GetWindowText(Cstring);
列表框和編輯框的組合,用戶除了可以在列表中對已經存在的選項進行選擇外,還可以輸入新的選擇。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("***"))
用來選擇一系列的可能選擇,用戶通過滾動條可以在這些選擇中瀏覽。在列表框中,可以進行單項選擇,也可以進行多項選擇,這取決于用戶在控件屬性對話框中的設置。MFC提供了CListBox類對列表框控件進行支持。
用來包圍具有邏輯關系的一組控件,在這些控件的周圍加上邊界和標題。需注意的是,組成框僅僅是在視覺效果上對控件進行“成組”,真正的“成組”工作還需要另外一些工作。僅僅在視覺上展現出一組的邏輯關系,并不添加任何代碼
用來選擇某種可能的選擇,與 (Check Box)復選框不同,該選項不是獨立的。
一般是幾個單選按鈕組成一組,同組中的單選按鈕僅有一個按鈕被選中。
MFC同樣使用CButton類對單選按鈕控件進行支持,
SetCheck()函數和GetCheck()函數對單選按鈕也是適用的。
用來在指定的位置顯示特定的字符串,一般用來標識附近另一個控件的內容。顯示在靜態文本控件中的字符串一般不再改變,但是在需要的時候,必須為其指定一個不同食物ID號,通過調用相應的函數來進行設置。MFC提供了CStatic類支持靜態控件。
顯示位圖(Bitmap)和圖標(Icon),圖形繪制與顯示,主要是其方形的區域適合顯示,同樣方形區域也可利用(Static Text)靜態文本框。
這包括水平滾動條和垂直滾動條,除了在視覺效果上的方向不同外,水平滾動條在被滾動時發生WM_HSCROLL消息,而垂直滾動條在被滾動時發送WM_VSCROLL消息。MFC提供了CScrollBar進行支持。
通常用來在程序中接受一系列離散的數值。
用戶可以設置滑塊控件的取值范圍,并可以為控件加上刻度標記以顯示特定位置的含義。
MFC提供了CSliderCtrl類進行支持。
包括一對緊靠在一起的上下箭頭,使用微調按鈕可以增大或者縮小某個特定的數值。
微調按鈕往往都需要一個“伙伴”控件,這通常都是一個編輯框。
當微調按鈕的向上箭頭被單擊時,編輯框中的數字就增大;反之則減小。MFC提供了CPinButtonCtrl類進行支持。
在進行一項需要較長時間的操作時來反應當前的進度。
當操作的進度不斷前進時,進度條就用特色顏色填充進度條框。用戶可以設定進度條的范圍和當前位置。
MFC提供了CProgressCtrl類進行支持。
CProgressCtrl* progressbar=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS_1);
progressbar->SetRange(0, 4);
progressbar->SetPos(0);
熱鍵控件看起來就像一個編輯框,但是在熱鍵控件中能夠立刻反應用戶剛剛按下的鍵組合,這在設置程序的熱鍵時特別有用。
熱鍵控件只是在“視覺”上顯示了按鍵組合,設置熱鍵的工作還需要用戶添加代碼完成。
MFC提供了CHotKey類進行支持。
按一定的排列順序顯示一系列帶圖標的字符串。
列表控件提供了四種顯示模式:大圖標(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 ++;
顯示一系列項目的層次關系,最典型的例子是顯示磁盤上的文件與文件夾。
如果有子項目的話,單擊樹形控件中的項目可以展開或者收縮其子項目。
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); } }
包含大量的控件,可以滿足用戶顯示或者獲取大量數據分類顯示的要求,典型例子是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;
}
用來播放一段AVI格式的視頻剪輯。用戶可以控制視頻剪輯的播放、停止和定位,但也僅限于這些功能。動畫控件設置不能播放音頻剪輯,如果用戶需要更高層次的視頻或者音頻的支持,請選用MCIWnd控件。
MFC提供了CAnimateCtrl類對動畫控件進行支持。
編輯控件(Edit Control)功能的擴展。在高級編輯框中,除了簡單的輸入和編輯字符串外,用戶還可以為字符或段落指定特定的格式,用戶甚至還可以向高級編輯框中插入OLE項。
高級編輯框基本上實現了一個帶格式的文本編輯器功能,而只需要用戶添加少量的接口。
MFC提供了CRichEditCtrl類進行支持。
向用戶提供了一種直觀的選擇日期和時間的方法、日期/時間選擇器在外觀上類似于一個組合框,但是當用戶單擊下拉箭頭時就會展開一個日歷控件供用戶選擇,而一旦用戶做出了選擇,日期/時間選擇器會自動顯示新的日期/時間。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);
如下圖,看似與真正的日歷類似,操作也類似,直觀的為用戶提供了觀察和顯示當前日期的途徑。MFC提供了CMonthCalCtrl類進行支持。
IP地址控件用來輸入和編輯IP地址,MFC提供了CIPAddressCtrl類進行支持。
該控件外觀類似于一個編輯框,但是可以自動對輸入的字符按3個一組進行區分和加間隔圓點。IP地址控件為開發支持Internet技術的程序提供了方便。
在普通組合框(Combo Box)的基礎上還支持圖像列表。
可以在組合框中顯示特定的圖標表示相應的選擇,而不僅僅是顯示文本。
MFC提供了CComboBoxEx類進行支持。
控件使用的時候,它的Class必須有一個類的支持這個窗口類可以VC的類,例如:Button、Edit.在頭文件增加一個CEdit類的成員變量:CEdit m_Text(即點擊右鍵添加變量),然后按照Edit控件使用即可。
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)控件一樣,響應相應的消息
如下圖,實現多選按鈕選擇功能,使用時添加相應菜單
可以直接作為inet_addr(ip)的輸入,分隔符為逗號(,)
不僅可以為按鈕添加相應命令還可以對命令做出注解
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++的項目學習視頻資料哦!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。