วันพุธที่ 27 มกราคม พ.ศ. 2559

Component EhLib


EhLib

 

Why was EhLib chosen in more

than 80 countries around the world?

EhLib is powerful and therewith intuitive to use!


Drop-Down Forms

Using the library, you will receive:
  • Maximum of enclosed functional during the work with tabular data.
  • Time saving for developer – display your data in the right format without writing software code.
  • Fast and intuitive exploration of the library.
  • Great number of examples, instructions and help-files.
  • High speed of applications – development involves a special optimization stage of speed for each component of library.
  • Easy debug final product. EhLib is 100% native VCL library written in Delphi language.
  • As a result the user will receive an understandable, beautiful and easy-to-use interface with impressive features of information processing.
Platform support: VCL, LCL
Support IDEs: Borland Delphi 7 – 2006, CodeGear Delphi 2007, RAD Studio 2009, Embarcadero RAD Studio 2010, XE - XE10, Lazarus (Win32).

วันอาทิตย์ที่ 15 ธันวาคม พ.ศ. 2556

System Watch สารพัดวิธีการเฝ้ามองระบบลีนุกซ์

System Watch สารพัดวิธีการเฝ้ามองระบบลีนุกซ์ copy จาก http://www.itdestination.com/articles/systemwatch/

โดย ธีรภัทร มนตรีศาสตร์,RHCE

ผู้บริหารจัดการระบบปฏิบัติการลีนุกซ์มีภาระหน้าที่ที่จะต้องดูแลระบบต่างๆ ภายในเครือข่ายให้มีความพร้อมอยู่เสมอที่จะทำหน้าที่ต่างๆ ที่ได้วางระบบไว้ หลังจากที่ระบบและแอปพลิเคชั่นทั้งหลายได้ทำงานเป็นไปตามที่ต้องการแล้ว ก็ไม่ได้หมายความว่า ภารกิจของผู้บริหารระบบจะหมดลง หากแต่ยังคงต้องเฝ้าตรวจตราความเปลี่ยนแปลงต่างๆ ที่เกิดขึ้นในระบบต่อไปอีกอย่างต่อเนื่อง เพื่อให้ระบบมีสภาพที่ดีอยู่เสมอ

จุดประสงค์ของการเฝ้ามองระบบ
การเฝ้ามองระบบ (System Watch) มีจุดประสงค์เพื่อ

  1. เพื่อทราบสถานะปัจจุบันของระบบปฏิบัติการและสภาพแวดล้อมของระบบ
  2. เพื่อทำการสังเกตและค้นหาความผิดปรกติที่เกิดขึ้นโดยเปรียบเทียบสภาพก่อนและหลังการกระทำอย่างใดอย่างหนึ่งต่อระบบ
  3. เพื่อปรับปรุงหรือแก้ไขความบกพร่องทั้งในด้านคุณลักษณะ ประสิทธิภาพ และความปลอดภัยให้แก่ระบบ
เครื่องมือเฝ้ามองระบบ ในการปฏิบัติงานด้านการเฝ้ามองระบบ (System Watch) เช่นนี้ ผู้บริหารระบบจำเป็นต้องอาศัยเครื่องมือต่างๆ เพื่อการเข้าถึงส่วนประกอบภายในระบบ มีการรายงานสภาพปัจจุบันของระบบ ช่วยให้ได้รับข้อมูลที่อ่านค่าและวิเคราะห์ได้ง่าย ซึ่งเครื่องมือที่ช่วยงานด้านนี้ อาจแบ่งออกได้ 2 กลุ่มใหญ่ๆ คือ

  1. เครื่องมือที่เป็นคำสั่งพื้นฐานของระบบปฏิบัติการ ซึ่งมีอยู่เป็นจำนวนมาก บางคำสั่งก็มีหน้าที่เฉพาะโดยตรงเกี่ยวกับการเฝ้ามองระบบ แต่บางคำสั่งไม่ได้มีหน้าที่ด้านนี้โดยตรง แต่จะเป็นการประยุกต์หรือใช้ในทางอ้อมแล้วจึงให้ผลที่เป็นประโยชน์ต่อการ เฝ้ามองระบบได้เช่นกัน
  2. เครื่องมือที่เป็นแอปพลิเคชั่นเพิ่มเติมจากภายนอก ซอฟต์แวร์ในกลุ่มนี้จะต้องจัดหามาติดตั้งเพิ่มเติมเอง มีขนาดและคุณสมบัติแตกต่างกันออกไป ส่วนใหญ่จึงมีคุณสมบัติที่ตอบสนองความต้องการได้ดีกว่าเครื่องมือในกลุ่มแรก แต่ก็จะต้องแลกด้วยความยุ่งยากในการติดตั้งก่อนที่จะใช้งานได้ และยังต้องศึกษาวิธีการใช้งาน ภายใต้เงื่อนไขที่ซอฟต์แวร์นั้นๆ กำหนดได้อีกด้วย

ดังนั้นจะเห็นว่า ลำพังเฉพาะคำสั่งพื้นฐานทั่วไปในระบบปฏิบัติการ ก็สามารถช่วยงานด้านการเฝ้ามองระบบได้แล้ว ทักษะในการใช้คำสั่งต่างๆ ของผู้ปฏิบัติงานจึงมีความสำคัญ และจำเป็นต้องศึกษาเพื่อสามารถนำมาใช้ได้ในสภาพการทำงานปรกติที่ต้องรู้ สถานะของระบบอยู่เสมอหรือทันทีทันใดที่ต้องการ
การแบ่งระดับการเฝ้ามองระบบ ระดับของสถานะของระบบ เป็นอีกสิ่งหนึ่งที่จะช่วยให้เราเข้าใจการเฝ้ามองระบบได้ดียิ่งขึ้น โดยเราอาจบ้างระบบออกเป็น 3 ระดับ ได้แก่
  1. ระดับเคอร์เนลและโปรเซส ซึ่งถือว่าเป็นระดับที่มองลึกลงไปในการทำงานภายในแกนกลางของระบบปฏิบัติการ ที่มีความเปลี่ยนแปลงต่างๆ เกิดขึ้นในโปรเซสเซอร์และหน่วยความจำ
  2. ระดับยูสเซอร์ สภาพแวดล้อมของระบบ และแอปพลิเคชั่นต่างๆ ส่วนนี้จะมีความหลากหลายของส่วนประกอบค่อนข้างมาก เกี่ยวข้องกับการเข้ามาใช้งานของยูสเซอร์(รวมทั้งแอปพลิเคชั่นต่างๆ ที่ทำงานโดยอาศัยชื่อบัญชียูสเซอร์) การจัดการเนื้อที่ดิสก์และระบบจัดเก็บไฟล์ และขยายขอบเขตไปถึงการทำงานของซอฟต์แวร์ประยุกต์ต่างๆ ในระบบอีกด้วย
  3. ระดับโปรโตคอล และระบบเครือข่าย ถือว่าเป็นส่วนที่ผู้ดูแลระบบลีนุกซ์เซิร์ฟเวอร์มักให้ความสำคัญค่อนข้างมาก กัน เพราะการทำงานภายในระบบปฏิบัติการลีนุกซ์จะอาศัยการไหลเวียนของโปรโตคอ ลต่างๆ ในการเชื่อมโยงสื่อสารการทำงานระหว่างกันนอกเหนือจากการสื่อสารให้บริการภาย นอกในฐานะไคลเอ้นต์หรือเซิร์ฟเวอร์ที่เราทราบกันดีอยู่แล้ว ดังนั้นการเฝ้ามองความเคลื่อนไหวเกี่ยวกับระบบเครือข่ายจึงเป็นเรื่องสำคัญ อย่างยิ่ง
คำสั่ง vmstat และ uptime ความเคลื่อนไหวและเปลี่ยนแปลงระดับเคอร์เนลและโปรเซส จะเป็นการสังเกตการทำงานภายในระบบปฏิบัติการที่เกี่ยวข้องกับการใช้ทรัพยากร ของระบบปฏิบัติการ เช่น โปรเซสเซอร์ หน่วยความจำประเภทต่างๆ ระบบอินพุตและเอาต์พุต เป็นต้น ข้อมูลต่างๆ ที่ได้จากการเฝ้ามองระบบส่วนนี้มักถูกนำไปใช้เพื่อการปรับแต่งค่าให้เหมาะสม กับความต้องการ (System Optimization) หรือการทดสอบความต้องการของระบบสำหรับการใช้งานซอฟต์แวร์แอปพลิเคชั่นต่างๆ คำสั่งพื้นฐานที่ทำหน้าที่นี้โดยเฉพาะคือ คำสั่ง vmstat ซึ่งคำว่า vm มาจากคำว่า Virtual Machine หมายถึงเคอร์เนลของระบบนั่นเอง vmstat จึงเป็นการรายงานสถานะ (status) ของเคอร์เนลในทุกๆ ด้าน โดยเราสามารถใช้คำสั่งนี้ประกอบกับอ๊อปชั่นของคำสั่งได้อย่างหลากหลาย อ๊อปชั่นที่ใช้เป็นประจำได้แก่
-a แสดงภาพรวมทั้งหมดในบรรทัดเดียว
-a 10 แสดงผลต่อเนื่องทุกๆ 10 วินาที
-a  -n 10 จะไม่แสดง header ทุกครั้งที่แสดงข้อมูล
-d แสดงสถานะการอ่านเขียนดิสก์
-s แสดงสถานะของ vm table




รูปที่ 1 ตัวอย่างผลลัพธ์คำสั่ง vmstat -d
ในการดูว่าเซิร์ฟเวอร์ของเรามีภาระงานมากหรือน้อย ถ้าคำสั่ง vmstat มีข้อมูลที่ละเอียดเกินไป สามารถใช้คำสั่ง uptime ทดแทนได้โดยจะแสดงเป็นค่า load average ให้ทราบโดยเป็นตัวเลข 3 ชุด แทนค่าเฉลี่ยของภาระของเซิร์ฟเวอร์ ย้อนหลัง 1 นาที 5 นาที และ 15 นาทีตามลำดับ คำสั่ง lsof คำสั่ง lsof ย่อมาจาก list opened files เป็นการแสดงรายชื่อโปรเซสที่กำลังเปิดไฟล์อยู่ มีประโยชน์มากในด้านการตรวจว่าโปรแกรมต่างๆ ที่กำลังทำงานอยู่เปิดไฟล์อะไรขึ้นมาบ้าง เป็นไฟล์ข้อมูล คำสั่ง หรือเป็น Unix Domain Socket ซึ่งมักจะมุ่งเน้นไปที่จุดประสงค์ในด้านความปลอดภัยเป็นสำคัญ เช่น ต้องการทราบว่าขณะนี้มีโปรแกรม Trojan ที่กำลังเปิดโปรแกรม perl อยู่หรือไม่ หรืออาจจะต้องการทราบว่า Socket แปลกปลอมที่ค้นพบกำลังถูกใช้งานโดยโปรเซสใดอยู่
การใช้งานคำสั่งนี้ทำได้โดยระบุชื่อไฟล์โปรแกรมหรือคำสั่งที่สนใจลงไป จะแสดงผลดังรูปที่ 2



รูปที่ 2 การใช้คำสั่ง lsof แสดงความสัมพันธ์ระหว่างโปรแกรมกับโปรเซส


ในทางกลับกัน หากเรามีโปรเซสที่เราสนใจ หรือค้นพบโปรเซสแปลกปลอมในระบบ ก็สามารถสืบย้อนกลับไปได้ว่าโปรเซสนั้นกำลังเปิดไฟล์ใดอยู่บ้าง โดยใช้คำสั่ง lsof -p xxxxx โดยที่ xxxxx เป็นหมายเลขโปรเซส (Process ID : PID) ของโปรเซสที่เราสนใจ ก็จะได้ผลลัพธ์เป็นรายชื่อไฟล์ที่กำลังถูกเปิดอยู่โดยโปรเซสนั้นๆ คำสั่ง ps และ top สำหรับการตรวจสอบดูว่าสถานะของโปรเซสทั้งหมดที่มีอยู่ในระบบ เราสามารถใช้คำสั่ง ps และ pstree ได้ ซึ่งคำสั่ง ps (Process Status) จะรายงานในลักษณะดังรูปที่ 3 เราจะเห็นความสัมพันธ์ของ
โปรเซสทั้งหลายได้อย่างชัดเจน โดยสาระสำคัญที่สุดคงเป็นตัวเลขซ้ายมือสุด ซึ่งเป็นหมายเลข
โปรเซส (PID)


รูปที่ 3 ตัวอย่างผลลัพธ์คำสั่ง ps aF
อย่างไรก็ตามคำสั่ง ps จะไม่สามารถแสดงสถานะเกี่ยวกับโปรเซสในระบบได้อย่างต่อเนื่อง ซึ่งอันที่จริงแล้วการทำงานของซอฟต์แวร์ต่างๆ ภายในระบบปฏิบัติการย่อมมีความเคลื่อนไหวเปลี่ยนแปลงอยู่ตลอดเวลา ผลลัพธ์ของคำสั่ง ps จึงไม่เหมาะกับการเฝ้ามองระบบนัก จึงควรใช้คำสั่ง top จะเหมาะสม
มากกว่า


รูปที่ 4 การมอนิเตอร์ภาพรวมของระบบด้วยคำสั่ง top
จากรูปที่ 4 จะเห็นว่าคำสั่ง top จะเป็นโปรแกรมคำสั่งที่เมื่อรันแล้วจะแสดงหน้าจอรายงานค้างอยู่และมีการ เปลี่ยนแปลงตลอดเวลา ช่วยให้เฝ้ามองระบบได้อย่างต่อเนื่อง นอกจากจะแสดงรายชื่อโปรเซสแล้ว เรายังสามารถจัดเรียงได้ตามเงื่อนไข เช่น เรียงตาม CPU load (กด Shift+P) หรือเรียงตามการใช้หน่วยความจำ (กด Shift+M) นอกจากนี้ยังสามารถบอกสถานะอื่นๆ ได้อีกในส่วนบนของจอภาพ เช่น บรรทัดแรกจะแสดงผลลัพธ์เหมือนผลลัพธ์คำสั่ง uptime บรรทัดที่สองแสดงสถานะ (STATE) ของโปรเซส บรรทัดที่ 3 แสดงสถานะของโปรเซสเซอร์ ส่วนบรรทัดที่ 4 และ 5 แสดงเกี่ยวกับหน่วยความจำ ทั้งนี้เนื่องจากคำสั่ง top เป็นคำสั่งพื้นฐานที่มาพร้อมกับระบบ การใช้งานอาจจะไม่สะดวก ไม่ถูกใจผู้ใช้งานนัก เช่น ไม่สามารถเลื่อน (Scroll) หน้าจอเพื่อลงไปดูโปรเซสทั้งหมดได้ การจัดหน้าจอก็ทำได้ไม่ง่ายนัก ดังนั้นจึงมีโปรแกรม htop เกิดขึ้น โดยผู้ใช้จะต้องดาวน์โหลดมาติดตั้งเพิ่มเติมเอง (กรณี Debian ใช้ aptitude ได้ทันที ส่วนผู้ใช้ Fedora สามารถใช้ yum ติดตั้งได้เช่นกัน) โปรแกรม htop ช่วยลดข้อจำกัดของคำสั่ง top ได้มากมาย เช่น ยินยอมให้ผู้ใช้จัดวางตำแหน่งแสดงข้อมูลได้เอง สามารถเลื่อนแถบสว่างไปยังโปรเซสที่ต้องการแล้วส่ง signal ไปได้โดยตรง สามารถเลือกสีการแสดงผลได้หลายรูปแบบ เป็นต้น หน้าตาของ htop แสดงดังรูปที่ 5


รูปที่ 5 โปรแกรม htop ที่มีคุณสมบัติเหนือกว่าคำสั่ง top
คำสั่งที่กี่ยวกับยูสเซอร์ สำหรับการทำงานในระดับยูสเซอร์ เราควรสามารถตรวจสอบและเฝ้ามองการกระทำของยูสเซอร์ได้ว่าเข้าออกเมื่อไหร่ มียูสเซอร์ใดกำลังใช้งานระบบอยู่บ้าง และมีการใช้ทรัพยากรอะไรอยู่บ้าง เราสามารถใช้คำสั่ง fuser เพื่อการตรวจสอบว่าไฟล์หรือไดเร็คทอรี่หรือ mount point ที่ระบุ กำลังถูกใช้งานอยู่หรือไม่โดยใครบ้าง ดังรูปที่ 6 แสดงให้เห็นว่า Socket ชื่อ fs7100 กำลังถูกใช้งานโดย root ผ่านโปรแกรมชื่อ xfs (X Font Server) ส่วนไดเร็คทอรี่ /www กำลังถูก mount โดย root อยู่จากระดับ kernel ในทางปฏิบัติคำสั่ง fuser นี้จึงช่วยให้เราแก้ไขปัญหาการ Unmount ไม่สำเร็จหรือ Device is busy ได้เพราะจะช่วยให้เราทราบว่าคำสั่งใดโดยโปรเซสใดที่กำลังใช้งาน mount point นั้นอยู่และเป็นสาเหตุของปัญหา


รูปที่ 6 การใช้คำสั่ง fuser แสดงการเปิดไฟล์ของยูสเซอร์
สำหรับการตรวจสอบว่า ณ เวลานี้มียูสเซอร์ใดกำลังอยู่ในระบบบ้าง สามารถตรวจสอบได้จากหลายคำสั่ง ได้แก่ คำสั่ง w คำสั่ง who และคำสั่ง last โดยที่คำสั่ง w เป็นการตอบคำถามว่ามีใคร (who) อยู่ในระบบบ้าง อยู่ที่เทอร์มินอลใดและมาจากที่ไหน (where) ล๊อกอินเข้ามาตั้งแต่เมื่อไหร่และนานเท่าไรแล้ว (when / how long) และขณะนี้กำลังทำอะไรอยู่ (what)


รูปที่ 7 เปรียบเทียบผลลัพธ์คำสั่ง w และ who
คำสั่ง who จะรายงานรายชื่อยูสเซอร์ที่ใช้งานในขณะนั้น หากใช้คำสั่ง who -Ha จะเห็นรายละเอียดที่มากยิ่งขึ้น รวมไปถึงการบูตระบบและ run level ที่สลับไปมาอีกด้วย ส่วนคำสั่ง last จะแสดงบันทึกของระบบเกี่ยวกับการเปิดปิดระบบ (boot/shutdown) และรายชื่อยูสเซอร์ที่ล๊อกอินในขณะปัจจุบัน รวมทั้งระยะเวลาและโฮสต์ที่ใช้งานแบบรีโมตเข้ามาอีกด้วย การจัดเก็บข้อมูลของคำสั่ง last นี้มีที่มาจากไฟล์ /va r/log/wtmp ซึ่งใช้ในการจัดเก็บข้อมูลการล๊อกอินย้อนหลังเอาไว้ สำหรับระบบของ Fedora Linux จะมีกลไกในการหมุนเวียนไฟล์นี้ทุกๆ เดือน (monthly) เพราะฉะนั้น หากมีความต้องการให้จัดเก็บนานมากขึ้นหรือน้อยลงก็สามารถปรับแต่งได้ที่ไฟล์ /etc/logrotate.conf


รูปที่ 8 ผลลัพธ์คำสั่ง last
การเฝ้ามองระดับเครือข่าย คำสั่งพื้นฐานทั่วไปบางครั้งสามารถนำมาประยุกต์ใช้ได้เป็นอย่างดี ในการเฝ้ามองระบบในระดับ
เครือ ข่ายก็เช่นกัน เช่น ถ้าเราต้องการรู้ว่ามีการติดต่อเข้าออกที่โฮสต์ของเรามากน้อยแค่ไหน คำสั่งง่ายๆ เช่น iptables ก็สามารถรายงานได้แล้ว ดังรูปที่ 9 จะเห็นว่าอ๊อปชั่น -v จะทำให้แสดงจำนวน
แพคเกตและไบต์ที่ไหลผ่าน chain ต่างๆ ได้ โดยเป็นปริมาณข้อมูลแบบภาพรวมนั่นเอง
ดังนั้นผู้บริหารระบบจึงสามารถประยุกต์ใช้คุณสมบัตินี้ของ iptables เพื่อการนับปริมาณข้อมูลที่ไหลผ่านตามเงื่อนไขได้โดยสร้าง Custom Defined Chains ขึ้นมา ประกอบกับการเขียนสคริปต์อีกเพียง
เล็กน้อยก็จะได้ระบบเฝ้ามองโปรโตคอลและทิศทางการสื่อสารขึ้นใช้งานแล้ว


รูปที่ 9 การใช้คำสั่ง iptables แสดงจำนวนแพคเก็ต
คำสั่ง netstat เป็นคำสั่งพื้นฐานด้านระบบเครือข่ายอีกคำสั่งหนึ่งที่สามารถนำมาประยุกต์ใช้ ในด้านการเฝ้ามองระบบได้ตั้งแต่การแสดงสถานะทั่วไป จนถึงการจับตาดูความเคลื่อนไหวแบบต่อเนื่อง ตัวอย่างในรูป 10 เป็นการแสดงให้เห็นว่าพอร์ตชนิด UDP ,TCP หมายเลขใดถูกเปิดใช้งานอยู่บ้าง (สถานะเป็น LISTEN) และโปรเซส(โปรแกรม)ใดเป็นผู้สร้างและควบคุมพอร์ตนั้นอยู่ หากต้องการแสดง Unix Domain Socket ที่กำลังเปิดอยู่ก็สามารถใช้อ๊อปชั่น -lnxp แทนได้ อ๊อปชั่น -rCn เป็นอีกหนึ่งวิธีใช้งานคำสั่งนี้ที่จะช่วยทำให้เห็น Cache Routing Table จากภายในเคอร์เนลได้ ซึ่งมีผลต่อทิศทางการกำหนดเส้นทางเดินของแพคเกตจากเครือข่ายหนึ่งไปยังเครือ ข่ายอื่นๆ ว่ามีกี่เส้นทางและเป็นเส้นทางที่มีประสิทธิภาพมากน้อยแค่ไหน อ๊อปชั่น -s (statistic) เป็นการแสดงรายงานสรุปสถิติหรือตัวนับจำนวนแพคเกตหรือค่าต่างๆแยกตาม
โปรโตคอล ช่วยให้เห็นภาพรวมของการรับส่งข้อมูลได้เป็นอย่างดี
อ๊อปชั่น -acXn ( X แทนได้ด้วยตัวอักษร t=TCP, u=UDP, x=unix ตามชนิดโปรโตคอลที่ต้องการ) เป็นการแสดงการติดต่อระหว่างโฮสต์ด้วยโปรโตคอลต่างๆ ที่เกิดขึ้นในปัจจุบันแบบเวลาจริงว่ามีสถานะใดเกิดขึ้นบ้าง โดยแสดงผลต่อเนื่องตลอดเวลา


รูปที่ 10 ตัวอย่างผลลัพธ์คำสั่ง netstat
จากการใช้งานคำสั่ง netstat อาจจะไม่สะดวก และรูปแบบการแสดงผลไม่สวยงามเท่าที่ควร โปรแกรมเสริมที่เป็นที่นิยมใช้ในการลักษณะนี้จึงเกิดขึ้นคือโปรแกรม IPTraf ซึ่งมีใช้งานในลีนุกซ์แทบทุก
ดิสทริบิวชั่น หมายความว่า โปรแกรมนี้มักจะมีมาพร้อมในชุดโปรแกรมติดตั้งลีนุกซ์เลยทีเดียว ตามรูปที่ 11 จะเห็นว่า เราสามารถใช้โปรแกรม IPTraf นี้ในการมอนิเตอร์ระบบเครือข่ายโดยแยกตามชนิดของโปรโตคอลได้อย่างสวยงาม ทำให้ง่ายต่อการอ่านผลลัพธ์ (รันโปรแกรมโดยใช้คำสั่ง iptraf -s eth0 )


รูปที่ 11 การใช้โปรแกรม iptraf แสดงพอร์ตที่เชื่อมต่ออยู่
นอกจากนี้ IPTraf ยังสามารถแสดงสถิติและการเชื่อมต่อในเครือข่ายในลักษณะอื่นๆ ได้อีกมาก ได้แก่ การแสดงสถิติแบ่งตามอินเทอร์เฟส การแสดงผลการเชื่อมต่อระหว่างโฮสต์ทั้งแบบ Connection Oriented Protocols และ Connectionless Oriented Protocols การแสดงปริมาณข้อมูลและแบนด์วิธแยกตามประเภทโปรโตคอล


รูปที่ 12 ตัวอย่างการใช้คำสั่ง watch
บางครั้งคำสั่งพื้นฐานบางคำสั่งจะไม่สามารถแสดงผลอย่างต่อเนื่องได้ อย่างเช่นคำสั่ง arp ซึ่งใช้ในการแสดงรายชื่อโฮสต์และ MAC Address จากตาราง ARP (ดังรูปที่ 12) และยังมีอีกหลายคำสั่งที่เป็นเช่นนี้ แต่ปัญหานี้สามารถแก้ไขได้ด้วยคำสั่ง watch ซึ่งถูกสร้างขึ้นมาเพื่อช่วยรันคำสั่งที่ระบุอย่างต่อเนื่องทุกๆ ช่วงเวลา 2 วินาที (หรือตามที่กำหนด) จึงทำให้เราสามารถเฝ้ามองการเปลี่ยนแปลงของผลลัพธ์คำสั่งต่างๆ ได้อย่างต่อเนื่อง เช่น เราต้องการรันคำสั่ง arp -e ทุกๆ 2 วินาทีก็จะใช้คำสั่งว่า # watch arp -e คือ พิมพ์คำสั่ง watch ตามด้วยบรรทัดคำสั่งที่ต้องการรันนั่นเอง ซอฟต์แวร์ที่ช่วยเฝ้ามองระบบโดยเฉพาะ ในระบบปฏิบัติการลีนุกซ์และยูนิกซ์แทบทุกดิสทริบิวชั่นจะมีแพคเกตซอฟต์ แวร์ชื่อ sysstat ซึ่งจะมีหน้าที่รวบรวมข้อมูลด้านต่างๆ ที่เกิดขึ้นในระบบปฏิบัติการไม่ว่าจะเป็นด้านโปรเซส หน่วยความจำ ดิสก์ และระบบเครือข่าย โดยจัดเก็บไว้ในฐานข้อมูลของมันเอง แล้วสร้างรายงานแจ้งให้เราทราบทุกๆ ช่วงเวลาที่กำหนด หรือจะเรียกดูทันทีก็ได้ โดยผ่านคำสั่ง sar จะได้รายงานดังรูป 13 นอกจากคำสั่ง sar แล้ว ยังมีคำสั่งย่อยอีก 2 คำสั่งที่มาพร้อมกันในแพคเกจนี้ คือ คำสั่ง mpstat สำหรับรายงานเกี่ยวกับ CPU และคำสั่ง iostat สำหรับรายงานเกี่ยวกับระบบดิสก


รูปที่ 13 รายงานที่ได้จากคำสั่ง sar
นอกจากการใช้งานในโหมดข้อความแล้ว ผู้ใช้งานที่นิยมการทำงานบนกราฟฟิกก็ยังมีโปรแกรม
สนับ สนุนการรายงานข้อมูลจากระบบได้เช่นกัน หากพิจารณาเท่าที่มีมาพร้อมแล้วในเดสทอปแบบ KDE จะมีแอปเพล็ตเล็กๆ ให้ติดตั้งใช้งานได้ทันที (ดังรูป 14) โดยคลิ๊กขวาบน Main Panel แล้วเลือก Add applet to panel... จากนั้นก็จะมีรายชื่อ Applet ให้เลือกติดตั้งได้ตามใจชอบ ที่เห็นนี้เป็น Applet ชื่อ System Guard และ System Monitor


รูปที่ 14 KDE Applet ที่ช่วยแสดงสถานะของระบบ
ส่วนสุดท้ายที่ผู้บริหารระบบลีนุกซ์ควรจะให้ความสนใจคือ ข้อมูลระบบจากพื้นที่ /proc ซึ่งจัดเก็บสถานะปัจจุบันของระบบไว้ โดยให้เข้าถึงได้เหมือนเป็นระบบไฟล์ระบบหนึ่ง เช่น /proc/cpuinfo จะเก็บสถานะของ CPU ของระบบ /proc/meminfo จะเก็บสถานะของหน่วยความจำ /proc/interrupts จะเก็บข้อมูลการจัดสรรสัญญาณขัดจังหวะของระบบไว้ เป็นต้น นอกจากจะใช้คำสั่งเปิดไฟล์มาอ่านโดยตรงแล้ว ใน KDE ยังให้โปรแกรมชื่อ KInfoCenter ไว้เพื่อเปิดข้อมูลมาอ่านได้สะดวกมากยิ่งขึ้นและแสดงผลเป็นกราฟฟิกที่อ่าน เข้าใจง่ายกว่าอีกด้วย


รูปที่ 15 การแสดงผลของ KInfoCenter
ความชำนาญเกิดจากการฝึกฝน เครื่องมือสำหรับการเฝ้ามองระบบ (System Watch) ที่นำเสนอนี้ ส่วนใหญ่จะเห็นว่าเป็นคำสั่งพื้นฐานที่มีอยู่แล้วในระบบ เราจะใช้เครื่องมือเหล่านี้ได้ชำนาญแค่ไหนนั้นขึ้นอยู่กับการฝึกฝนที่จำเป็น ต้องอยู่บนพื้นฐานของความรู้ ความเข้าใจ และอุทิศเวลาให้กับการลงมือทำอย่างจริงจัง โดยที่จะเป็นผู้บริหารระบบลีนุกซ์ที่ดีได้นั้นจะต้องตระหนักถึงการปฏิบัติ งานภายใต้สถานการณ์ 1) เป็น Text Console 2) ไม่มีโปรแกรมพิเศษใดๆ ติดตั้งไว้ และ 3) ต้องแข่งกับเวลา เครื่องมือ/คำสั่งพื้นฐานเพื่อการเฝ้ามองระบบในลีนุกซ์มีอะไรบ้างจะใช้ ประโยชน์ได้อย่างไรถึงเวลาที่ต้องศึกษาและทบทวนกันอันจะเป็นพื้นฐานไปสู่การ เฝ้าระวังระบบที่ซับซ้อนยิ่งขึ้นในอนาคต

Delphi Thread sendmessage

type
  TThreadWithMsg = class(TThread)
  private
    { Private declarations }
    procedure WMUser(var Msg: TWMNoParams); message WM_USER;
  protected
    procedure Execute; override;
  end;

{ TThreadWithMsg }
procedure TThreadWithMsg.Execute;
var
  Msg: TMsg;
  DMsg: TMessage;
begin
  PeekMessage(Msg,0,0,0,PM_NOREMOVE); // Create Message Queue
  while not Terminated do begin
     Sleep(10); // don't eat CPU cycles
     if PeekMessage(Msg,0,0,0,PM_REMOVE) then begin
       DMsg.Msg:=Msg.message;
       DMsg.wParam:=Msg.wParam;
       DMsg.lParam:=Msg.lParam;
       DMsg.Result:=0;
       Dispatch(DMsg);
     end;
  end;
end;

procedure TThreadWithMsg.WMUser(var Msg: TWMNoParams);
begin
  Beep(440,100);
end;

{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
  MyThread:=TThreadWithMsg.Create(False);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  MyThread.Terminate;
  MyThread.WaitFor;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostThreadMessage(MyThread.ThreadID,WM_USER,0,0);
end;

คำสั่ง top บน linux บอกอะไรได้บ้าง

คำสั่ง top บน linux บอกอะไรได้บ้าง

http://www.admin.in.th/webboard/index.php?topic=442.0



(capture ช้าไปสองวิ เสียดายจัง)

ไม่ต้องลงเพิ่ม ติดมากับ os อยู่แล้วไม่ว่าจะลงแบบ minimal ขนาดไหน
หรือถ้าทำหายไป มันจะอยู่ใน package "procps" ครับ

มันบอกอะไรบ้าง
ไล่ทีละบรรทัดเลยนะครับ (คิดจากค่าปกติของ centos ซึ่ง os อื่นๆ ก็คล้ายๆ กัน อาจมีแตกต่างบ้างแล้วแต่การปรับตั้งค่า)

บรรทัดบนสุด
top - 09:13:20 up 187 days, 8:40,1 user, load average: 0.43, 0.66, 0.61
สีแดง: เวลาปัจจุบันของ server
สีเขียว: uptime (ระยะเวลาตั้งแต่ boot OS ขึ้นมา)
สีม่วง: จำนวน user ที่ login เข้าไปใน shell (การ login หน้าเครื่อง + ssh ที่เปิด terminal เท่านั้น)
สีน้ำเงิน: load average : ปริมาณงานที่ "ค้าง" ในระบบเฉลี่ย ในรอบ 1 , 5 และ 15 นาทีตามลำดับ

บรรทัดที่ 2: บรรทัดนี้จะบอกข้อมูลเกี่ยวกับ process ในเครื่องครับ
Tasks: 183 total, 3 running, 180 sleeping, 0 stopped, 0 zombie
สีแดง: จำนวน process ทั้งหมด
สีเขียว: จำนวน process ที่กำลังเรียกใช้ CPU อยู่ "ณ เวลานั้นๆ"
สีม่วง: จำนวน process ที่ไม่มีการทำงาน/ไม่มีการเรียกใช้ CPU อยู่
สีน้ำเงิน: process ที่อยู่ในสถานะ "หยุด" (ไอนี้ไม่แน่ใจครับ คู่มือมันเขียนแบบนั้นแต่ผมไม่เคยเห็นตัวเลขขึ้นซักที)
สี ชมพู: process ผีดิบ lol มันคือ process ที่ตาย/จบการทำงานไปแล้ว แต่ยังไม่สามารถ clear ออกจากหน่วยความจำได้ ส่วนมากจะเป็นพวก process ที่รอการตอบสนองจาก hardware ต่างๆ อยู่ครับ (รวมถึงแรมด้วย

บรรทัดที่ 3: การใช้งาน CPU อันนี้มีของเล่นนิดหน่อยครับ สำหรับเครื่องที่ cpu หลาย core หรือหลาย cpu
Cpu(s): 4.0%us, 0.7%sy, 0.0%ni, 94.1%id, 0.9%wa, 0.0%hi, 0.3%si, 0.0%st

สังเกตดีๆ มันจะเขียนหน้าบรรทัดว่า Cpu(s) <-- ตรง (s) หมายความว่าเป็นภาพรวม cpu ทุก core
ให้กดแป้นพิมพ์เลข 1 ตรงแป้นพิมพ์ธรรมดา ที่อยู่ข้างๆ ปุ่มตัวหนอน (` / ~) แล้วมันจะแตกออกมาเป็นแบบนี้ครับ

Cpu0 : 27.6%us, 7.2%sy, 0.2%ni, 53.6%id, 10.9%wa, 0.0%hi, 0.5%si, 0.0%st
Cpu1 : 28.1%us, 7.2%sy, 0.1%ni, 55.3%id, 9.0%wa, 0.0%hi, 0.4%si, 0.0%st
Cpu2 : 27.8%us, 7.0%sy, 0.2%ni, 62.0%id, 2.8%wa, 0.0%hi, 0.2%si, 0.0%st
Cpu3 : 28.1%us, 7.3%sy, 0.2%ni, 58.8%id, 3.4%wa, 0.2%hi, 2.1%si, 0.0%st

แยกกันให้เห็นหมดเลย ว่า CPU ไหนกำลังทำอะไรอยู่
ทีนี้ แต่ละ column ที่มีตัวอักษรย่อสองตัว มีความหมายต่างกันตามนี้ครับ

us => user :: เป็นการเรียกใช้ CPU ตามปกติของโปรแกรม ที่เป็นการประมวลผลภายในโปรแกรมนั้นๆ
sy => system :: การเรียกใช้คำสั่งในระดับ kernel ที่มีการประมวลผลอยู่ภายใน kernel โดยไม่เรียกใช้ hardware
ni => nice :: การจัดลำดับความสำคัญของการประมวลผล (priority) ไว้สลับการทำงานของ process ที่มี priority ต่างๆ กันเวลาเรียกใช้ cpu พร้อมๆ กัน
id => idle :: cpu ที่ว่างงาน
wa => iowait :: เป็นการ 'เสียเวลารอ' การเรียกใช้ และติดต่อกับ hardware ตั้งแต่ harddisk ram การ์ดจอ การ์ดแลน (แต่ส่วนใหญ่ก็ harddisk แหละ)
hi => ?
si => ? (สามอันนี้ขออภัยด้วยครับ ไม่ทราบจริงๆ ส่วนมากก็ไม่ค่อยขึ้นมาให้เห็นเท่าไหร่ด้วย)
st => ?

บรรทัดที่ 4-5: เกี่ยวกับหน่วยความจำ ขอรวบเป็นหัวข้อเดียวเลยนะครับ เพราะมันเกี่ยวข้องกัน
Mem: 8310380k total, 4970936k used, 3339444k free, 217448k buffers
Swap: 6225904k total, 52816k used, 6173088k free, 3001860k cached
สีแดง: RAM ทั้งหมดที่ติดตั้งไว้ และ OS มองเห็น (หมายถึงหน่วยความจำหลักอย่างเดียวครับ)
สีชมพู: ใช้แรมไปแล้ว "ทั้งหมด" เท่าไหร่
สีเขียว: แรมที่ยังว่างจริงๆ (คือไม่ได้จองให้กับอะไรเลย)
สีส้ม: แรมที่ถูกใช้เป็น buffer ที่พักข้อมูลก่อนที่จะมีการอ่าน/เขียนลง harddisk หรือ CPU
สีม่วง: swap space พื้นที่แรมเสมือนทั้งหมด ที่ใช้พื้นที่จาก harddisk เก็บข้อมูลแทนแรม --- บน windows มันจะมีชื่อว่า pagefile
สี น้ำเงิน: ปริมาณการใช้งาน swap space มากน้อยไม่ใช่ปัญหาเท่าไหร่ (ถึงมันจะไม่ควรใช้ก็ตาม) แต่ถ้าตัวเลขแกว่งไปมา (พร้อมกับ iowait พุ่ง) หมายความว่ามีปัญหาแรมไม่พอจนต้องมาเขียนลง swap space
สีน้ำตาล: พื้นที่ swap space ที่ไม่ได้ใช้งาน
สี ดำ: เป็น file system memory cache ครับ คือ linux จะมีการใช้ ram เพื่อเก็บข้อมูลไฟล์ที่มีการเรียกใช้งานบ่อยๆ ไว้ใน ram (เผื่อมีอะไรก็อ่านเอาจากแรมไปเลย เร็วกว่าเยอะ)

วิธีคิดพื้นที่แรมว่าง ให้คิดจาก free + cached ไม่นับพื้นที่ cache เป็นพื้นที่ที่มีการใช้งาน
เพราะมันจะถูกลบออกได้เสมอถ้ามีความต้องการใช้แรมจาก process เยอะๆ


ส่วนพื้นที่ที่เหลือด้านล่าง จะเป็นรายการ process ทั้งหมด (แสดงเท่าที่พื้นที่จอเหลือ)
เรียงลำดับตามปริมาณการใช้งาน CPU ของ process นั้นๆ (เปลี่ยนได้ครับ)

มีหัวข้อตามนี้
PID : หมายเลข process id
USER : user ที่ process ทำงาน
PR : priority ของ process ที่ nice เท่ากัน
NI : รหัส nice เรียงความสำคัญของ process (ยิ่งน้อยยิ่งสำคัญ)
VIRT : ปริมาณการใช้งาน virtual image ทั้งหมด (ตั้งแต่ process ยันเตไปถึงการเรียก library)
RES / SHR : การใช้แรมส่วนของ private (เฉพาะภายใน app) / shared (ram กลางของระบบ)
S : สถานะของ process
%CPU : ปริมาณการใช้งาน CPU (นับต่อ core นะครับ) สมมติ cpu 4 core + process รัน 4 thread แต่ละ thread เรียกใช้ cpu เต็มที่ มันก็ขึ้น 400 ขึ้นมาได้เหมือนกัน
%MEM : ปริมาณการใช้งาน ram เป็น %
TIME+ : "ระยะเวลา" ที่เรียกใช้ CPU ทั้งหมดตั้งแต่รัน process (เพราะ process ไม่ได้ทำงานตลอดเวลา)
COMMAND : คำสั่งที่ใช้รัน process

top สามารถหาอ่านได้จากคำสั่ง man top นะครับ


คัดลอกมาจากhttp://www.admin.in.th/webboard/index.php?topic=442.0

วันพฤหัสบดีที่ 5 เมษายน พ.ศ. 2555

Simple Generics Type Example

Simple Generics Type Example

Here’s how to define a simple generic class:
type
  TGenericContainer<T> = class
  Value : T;
 end;
With the following definition, here’s how to use an integer and string generic container:
var
  genericInt : TGenericContainer<integer>;
  genericStr : TGenericContainer<string>;
begin
  genericInt := TGenericContainer<integer>.Create;
  genericInt.Value := 2009; //only integers
  genericInt.Free;
 
  genericStr := TGenericContainer<string>.Create;
  genericStr.Value := 'Delphi Generics'; //only strings
  genericStr.Free;
end;

วันจันทร์ที่ 26 มีนาคม พ.ศ. 2555

Calling CreateProcess() the easy way

If you look up the CreateProcess() function in Win32 help, you'll notice that there are more than three dozen parameters that you can optionally setup before calling it. The good news is that you have to setup only a small number of those parameters to make a simple CreateProcess() call as demonstrated in the following function:
function CreateProcessSimple(sExecutableFilePath: string ): string;
var
  pi: TProcessInformation;
  si: TStartupInfo;
begin
  FillMemory(@si, sizeof(si), 0);
  si.cb := sizeof(si);

  CreateProcess(
    nil,
    PChar( sExecutableFilePath ),     // path to the executable file:
    nil, nil, False,
    NORMAL_PRIORITY_CLASS, nil, nil,
    si, pi
  );

  // "after calling code" such as
  // the code to wait until the
  // process is done should go here  
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);
end;
Now, all you have to do is call CreateProcessSimple(), let's say to run Windows' Notepad:
CreateProcessSimple('notepad');

วันพุธที่ 21 มีนาคม พ.ศ. 2555

Strings in Case statements

function CaseOfString(s: string; a: array of string): Integer;
begin
  
Result := 0;
  while (Result < Length(a)) and (a[Result] <> s) do
    
Inc(Result);
  if a[Result] <> s then
    
Result := -1;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  case 
CaseOfString(Edit1.Text, ['42', '23', 'nerd alert', 'hello world']) of
    
0: Label1.Caption := 'What is six times nine?';
    1: Label1.Caption := 'Nichts ist, wie es scheint...';
    2: Label1.Caption := 'BATMAAAAAAAN!';
    3: Label1.Caption := 'Hello people.';
    else
      
Label1.Caption := '?';
  end;
end;

check, if a directory is empty?

function DirectoryIsEmpty(Directory: string): Boolean;
var
  
SR: TSearchRec;
  i: Integer;
begin
  
Result := False;
  FindFirst(IncludeTrailingPathDelimiter(Directory) + '*', faAnyFile, SR);
  for i := 1 to do
    if 
(SR.Name = '.') or (SR.Name = '..') then
      
Result := FindNext(SR) <> 0;
  FindClose(SR);
end;


// Beispiel:
// Example:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if 
DirectoryIsEmpty('C:\test') then
    
Label1.Caption := 'empty'
  else
    
Label1.Caption := 'not empty';
end;

show a form without focusing

...show a form without focusing



//in TCustomForm class,in protected section add

    
procedure ShowParam(var param : integer);dynamic;
    {
    this procedure call when form should be show,
    now you should override this method and write your option for
    ShowWindow API. see the example
    }
    
function InShowFocus : boolean ;dynamic;
    //this function determine that after show the Form , focus on it or no.

//and it's code is

procedure TCustomForm.ShowParam(var param: Integer);
const
  
ShowCommands: array[TWindowState] of Integer =
    (SW_SHOWNORMAL, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED);
begin
  
param := ShowCommands[FWindowState];
end;

function TCustomForm.InShowFocus: Boolean;
begin
  
Result := True;
end;
//-------------------------------------------------------
//now in your class you can use from themunit Unit2;

interface

uses
  
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls;

type
  
TForm2 = class(TForm)
  private
    
{ Private declarations }
  
protected
    procedure 
ShowParam(var param: Integer); override;
    function InShowFocus: Boolean; override;
  public
    
{ Public declarations }
  
end;

var
  
Form2: TForm2;

implementation

{$R *.dfm}

{ TForm2 }

function TForm2.InShowFocus: Boolean;
begin
  
Result := False;
end;

procedure TForm2.ShowParam(var param: Integer);
begin
  inherited
;
  param := SW_SHOWNOACTIVATE;
end;

end.

วันจันทร์ที่ 12 มีนาคม พ.ศ. 2555

Show the select directory dialog

uses Filectrl;


procedure TForm1.Button1Click(Sender: TObject);
var
  Dir: String;
begin
  SelectDirectory('Select a directory', '', Dir);
  ShowMessage(Dir);
end;

//Dir is the selected directory

Set date/time of the file

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Edit1.Text:=OpenDialog1.FileName;
end;


procedure TForm1.Button2Click(Sender: TObject);
var
  HFile: Word;
  MyDate: TDateTime;
  MyDate2: Integer;
begin
  HFile:=FileOpen(Edit1.Text, fmOpenWrite);
  MyDate:=StrToDateTime(Edit2.Text);
  MyDate2:=DateTimeToFileDate(MyDate);
  FileSetDate(HFile, MyDate2);
  FileClose(HFile);
end;

Simulate the pressing of keyboard keys

{1. PostKeyEx32 function}

procedure PostKeyEx32(key: Word; const shift: TShiftState; specialkey: Boolean);
{************************************************************
* Procedure PostKeyEx32
*
* Parameters:
*  key    : virtual keycode of the key to send. For printable
*           keys this is simply the ANSI code (Ord(character)).
*  shift  : state of the modifier keys. This is a set, so you
*           can set several of these keys (shift, control, alt,
*           mouse buttons) in tandem. The TShiftState type is
*           declared in the Classes Unit.
*  specialkey: normally this should be False. Set it to True to
*           specify a key on the numeric keypad, for example.
* Description:
*  Uses keybd_event to manufacture a series of key events matching
*  the passed parameters. The events go to the control with focus.
*  Note that for characters key is always the upper-case version of
*  the character. Sending without any modifier keys will result in
*  a lower-case character, sending it with [ssShift] will result
*  in an upper-case character!
************************************************************}

type
  TShiftKeyInfo = record
    shift: Byte;
    vkey: Byte;
  end;
  byteset = set of 0..7;
const
  shiftkeys: array [1..3] of TShiftKeyInfo =
    ((shift: Ord(ssCtrl); vkey: VK_CONTROL),
    (shift: Ord(ssShift); vkey: VK_SHIFT),
    (shift: Ord(ssAlt); vkey: VK_MENU));
var
  flag: DWORD;
  bShift: ByteSet absolute shift;
  i: Integer;
begin
  for i := 1 to 3 do
  begin
    if shiftkeys[i].shift in bShift then
      keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
  end; { For }
  if specialkey then
    flag := KEYEVENTF_EXTENDEDKEY
  else
    flag := 0;
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  flag := flag or KEYEVENTF_KEYUP;
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  for i := 3 downto 1 do
  begin
    if shiftkeys[i].shift in bShift then
      keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0),
        KEYEVENTF_KEYUP, 0);
  end; { For }
end; { PostKeyEx32 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostKeyEx32(VK_LWIN, [], False);
  PostKeyEx32(Ord('D'), [], False);
  PostKeyEx32(Ord('C'), [ssctrl, ssAlt], False);
end;
{************************************************************}
{2. With keybd_event API}

procedure TForm1.Button1Click(Sender: TObject);
begin
  {or you can also try this simple example to send any
   amount of keystrokes at the same time. }

  {Pressing the A Key and showing it in the Edit1.Text}
  Edit1.SetFocus;
  keybd_event(VK_SHIFT, 0, 0, 0);
  keybd_event(Ord('A'), 0, 0, 0);
  keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
  {Presses the Left Window Key and starts the Run}
  keybd_event(VK_LWIN, 0, 0, 0);
  keybd_event(Ord('R'), 0, 0, 0);
  keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
end;
{***********************************************************}
{3. With keybd_event API}

procedure PostKeyExHWND(hWindow: HWnd; key: Word; const shift: TShiftState;
  specialkey: Boolean);
{************************************************************
* Procedure PostKeyEx
*
* Parameters:
*  hWindow: target window to be send the keystroke
*  key    : virtual keycode of the key to send. For printable
*           keys this is simply the ANSI code (Ord(character)).
*  shift  : state of the modifier keys. This is a set, so you
*           can set several of these keys (shift, control, alt,
*           mouse buttons) in tandem. The TShiftState type is
*           declared in the Classes Unit.
*  specialkey: normally this should be False. Set it to True to
*           specify a key on the numeric keypad, for example.
*           If this parameter is true, bit 24 of the lparam for
*           the posted WM_KEY* messages will be set.
* Description:
*  This
procedure sets up Windows key state array to correctly
*  reflect the requested pattern of modifier keys and then posts
*  a WM_KEYDOWN/WM_KEYUP message pair to the target window. Then
*  Application.ProcessMessages is called to process the messages
*  before the keyboard state is restored.
* Error Conditions:
*  May fail due to lack of memory for the two key state buffers.
*  Will raise an exception in this case.
* NOTE:
*  Setting the keyboard state will not work across applications
*  running in different memory spaces on Win32 unless AttachThreadInput
*  is used to connect to the target thread first.
*Created: 02/21/96 16:39:00 by P. Below
************************************************************}

type
  TBuffers = array [0..1] of TKeyboardState;
var
  pKeyBuffers: ^TBuffers;
  lParam: LongInt;
begin
  (* check if the target window exists *)
  if IsWindow(hWindow) then
  begin
    (* set local variables to default values *)
    pKeyBuffers := nil;
    lParam := MakeLong(0, MapVirtualKey(key, 0));
    (* modify lparam if special key requested *)
    if specialkey then
      lParam := lParam or $1000000;
    (* allocate space for the key state buffers *)
    New(pKeyBuffers);
    try
      (* Fill buffer 1 with current state so we can later restore it.
         Null out buffer 0 to get a "no key pressed" state. *)
      GetKeyboardState(pKeyBuffers^[1]);
      FillChar(pKeyBuffers^[0], SizeOf(TKeyboardState), 0);
      (* set the requested modifier keys to "down" state in the buffer*)
      if ssShift in shift then
        pKeyBuffers^[0][VK_SHIFT] := $80;
      if ssAlt in shift then
      begin
        (* Alt needs special treatment since a bit in lparam needs also be set *)
        pKeyBuffers^[0][VK_MENU] := $80;
        lParam := lParam or $20000000;
      end;
      if ssCtrl in shift then
        pKeyBuffers^[0][VK_CONTROL] := $80;
      if ssLeft in shift then
        pKeyBuffers^[0][VK_LBUTTON] := $80;
      if ssRight in shift then
        pKeyBuffers^[0][VK_RBUTTON] := $80;
      if ssMiddle in shift then
        pKeyBuffers^[0][VK_MBUTTON] := $80;
      (* make out new key state array the active key state map *)
      SetKeyboardState(pKeyBuffers^[0]);
      (* post the key messages *)
      if ssAlt in Shift then
      begin
        PostMessage(hWindow, WM_SYSKEYDOWN, key, lParam);
        PostMessage(hWindow, WM_SYSKEYUP, key, lParam or $C0000000);
      end
      else
      begin
        PostMessage(hWindow, WM_KEYDOWN, key, lParam);
        PostMessage(hWindow, WM_KEYUP, key, lParam or $C0000000);
      end;
      (* process the messages *)
      Application.ProcessMessages;
      (* restore the old key state map *)
      SetKeyboardState(pKeyBuffers^[1]);
    finally
      (* free the memory for the key state buffers *)
      if pKeyBuffers <> nil then
        Dispose(pKeyBuffers);
    end; { If }
  end;
end; { PostKeyEx }

procedure TForm1.Button1Click(Sender: TObject);
var
  targetWnd: HWND;
begin
  targetWnd := FindWindow('notepad', nil)
    if targetWnd <> 0 then
    begin
      PostKeyExHWND(targetWnd, Ord('I'), [ssAlt], False);
  end;
end;
{***********************************************************}
{3. With SendInput API}

procedure TForm1.Button1Click(Sender: TObject);
const
   Str: string = 'writing writing writing';
var
  Inp: TInput;
  I: Integer;
begin
  Edit1.SetFocus;
  for I := 1 to Length(Str) do
  begin
    Inp.Itype := INPUT_KEYBOARD;
    Inp.ki.wVk := Ord(UpCase(Str[i]));
    Inp.ki.dwFlags := 0;
    SendInput(1, Inp, SizeOf(Inp));
    Inp.Itype := INPUT_KEYBOARD;
    Inp.ki.wVk := Ord(UpCase(Str[i]));
    Inp.ki.dwFlags := KEYEVENTF_KEYUP;
    SendInput(1, Inp, SizeOf(Inp));
    Application.ProcessMessages;
    Sleep(80);
  end;
end;

procedure SendAltTab;
var
  KeyInputs: array of TInput;
  KeyInputCount: Integer;
 
procedure KeybdInput(VKey: Byte; Flags: DWORD);
  begin
    Inc(KeyInputCount);
    SetLength(KeyInputs, KeyInputCount);
    KeyInputs[KeyInputCount - 1].Itype := INPUT_KEYBOARD;
    with  KeyInputs[KeyInputCount - 1].ki do
    begin
      wVk := VKey;
      wScan := MapVirtualKey(wVk, 0);
      dwFlags := KEYEVENTF_EXTENDEDKEY;
      dwFlags := Flags or dwFlags;
      time := 0;
      dwExtraInfo := 0;
    end;
  end;
begin
  KeybdInput(VK_MENU, 0);                // Alt
  KeybdInput(VK_TAB, 0);                 // Tab
  KeybdInput(VK_TAB, KEYEVENTF_KEYUP);   // Tab
  KeybdInput(VK_MENU, KEYEVENTF_KEYUP); // Alt
  SendInput(KeyInputCount, KeyInputs[0], SizeOf(KeyInputs[0]));
end;

Hi!Delphi !

http://www.hidelphi.com/

Android MySQL Connectivity via JSON

Android MySQL Connectivity via JSON

http://appinventor.blogspot.com/search/label/android

Rave Report PDF and Intraweb

http://www.felix-colibri.com/papers/db/rave_pdf_intraweb/rave_pdf_intraweb.html

วันจันทร์ที่ 6 กุมภาพันธ์ พ.ศ. 2555

How to track a user's idle time

function SecondsIdle: DWord;
var
   liInfo: TLastInputInfo;
begin
   liInfo.cbSize := SizeOf(TLastInputInfo) ;
   GetLastInputInfo(liInfo) ;
   Result := (GetTickCount - liInfo.dwTime) DIV 1000;
end;

procedure TForm1.Timer1Timer(Sender: TObject) ;
begin
   Caption := Format('System IDLE last %d seconds', [SecondsIdle]) ;
end;

วันพฤหัสบดีที่ 2 กุมภาพันธ์ พ.ศ. 2555

DevExpress GetSkinNames

procedure GetSkinNames(aList: TStrings);
var
  i : Integer;
begin
  for i := 0 to Pred(cxLookAndFeelPaintersManager.Count ) do
    AList.Add( cxLookAndFeelPaintersManager.Items[ i ].LookAndFeelName );
end;
/////////////////
uses
...., cxLookAndFeelPainters, dxSkinInfo, dxGDIPlusClasses;

procedure GetSkinNamesAndIcon(aList: TStrings; aImageList16 : TcxImageList);
var
  i         : Integer;
  fDetails  : TdxSkinDetails;
  fIcon     : TdxPNGImage;
  fPainter  : TcxCustomLookAndFeelPainter;
  fSkinInfo : TdxSkinInfo;
  fImg      : TBitmap;
  fTempList : TStrings;
begin
  fImg := TBitmap.Create;
  fTempList := TStringList.Create;
  try
    for i := 0 to Pred( cxLookAndFeelPaintersManager.Count ) do
    begin
      fTempList.Add( cxLookAndFeelPaintersManager.Items[ i ].LookAndFeelName );
    end;
    for i := 0 to Pred( fTempList.Count ) do
    begin
      cxLookAndFeelPaintersManager.GetPainter(fTempList[i], fPainter);
      fPainter.GetPainterData(fSkinInfo) ;
      if fPainter.GetPainterDetails(fDetails) then
      begin
        aList.Add(fTempList[i]);
        fIcon := fDetails.Icons[sis16];
        fImg.Assign(fIcon);
        aImageList16.Add(fImg, Nil);
      end;
    end;
  finally
    fImg.Free;
    fTempList.Free;
  end;
end;

วันพุธที่ 1 กุมภาพันธ์ พ.ศ. 2555

วันอังคารที่ 31 มกราคม พ.ศ. 2555

convert a WideString to a String

{:Converts Unicode string to Ansi string using specified code page.
  @param   ws       Unicode string.
  @param   codePage Code page to be used in conversion.
  @returns Converted ansi string.
}

function WideStringToString(const ws: WideString; codePage: Word): AnsiString;
var
  
l: integer;
begin
  if 
ws = ' then
    Result := '
  else
  begin
    
l := WideCharToMultiByte(codePage,
      WC_COMPOSITECHECK or WC_DISCARDNS or WC_SEPCHARS or WC_DEFAULTCHAR,
      @ws[1], - 1, nil, 0, nilnil);
    SetLength(Result, l - 1);
    if l > 1 then
      
WideCharToMultiByte(codePage,
        WC_COMPOSITECHECK or WC_DISCARDNS or WC_SEPCHARS or WC_DEFAULTCHAR,
        @ws[1], - 1, @Result[1], l - 1, nilnil);
  end;
end{ WideStringToString }


{:Converts Ansi string to Unicode string using specified code page.
  @param   s        Ansi string.
  @param   codePage Code page to be used in conversion.
  @returns Converted wide string.
}
function StringToWideString(const s: AnsiString; codePage: Word): WideString;
var
  
l: integer;
begin
  if 
s = ' then
    Result := '
  else
  begin
    
l := MultiByteToWideChar(codePage, MB_PRECOMPOSED, PChar(@s[1]), - 1, nil, 0);
    SetLength(Result, l - 1);
    if l > 1 then
      
MultiByteToWideChar(CodePage, MB_PRECOMPOSED, PChar(@s[1]),
        - 1, PWideChar(@Result[1]), l - 1);
  end;
end{ StringToWideString }

Delphi字符和字符串-Char(AnsiChar)、WideChar与编码的相互转换

Delphi字符和字符串-Char(AnsiChar)、WideChar与编码的相互转换

作者 RadXE 发布时间 2012-01-30 03:45 文章分类 Delphi, 程序设计 文章评论 抢沙发 阅读次数 1阅读次数:9
//Char 类型与其编码值的转换:
var
  b: Byte;
  c: Char;
begin
  b := Ord('A');   {返回: 65}
  b := Ord(#65);   {返回: 65}
  b := Ord($41);   {返回: 65}
  b := Ord(#$41);  {返回: 65}

  b := Byte('A');  {返回: 65}
  b := Byte(#65);  {返回: 65}
  b := Byte($41);  {返回: 65}
  b := Byte(#$41); {返回: 65}

  c := Chr(65);    {返回: A }
  c := Chr($41);   {返回: A }

  c := Char(65);   {返回: A }
  c := Char($41);  {返回: A }
end;

//WideChar 类型与其编码值的转换; 汉字的 UniCode 编码范围是: $4E00..$9FA5
var
  w : Word;
  c : WideChar;
  ws: WideString;
  s : string;
begin
  {准备工作}
  ws := '万一';
  c := ws[1];
  //ShowMessage(c); {万}

  {从汉字到 UniCode 编码}
  w := Ord(c);                  {返回十进制数        : 19975}
  w := Word(c);                 {返回十进制数        : 19975}
  s := Format('%.4x',[Ord(c)]); {返回十六进制的字符串: 4E07 }
  s := IntToHex(Ord(c), 4);     {返回十六进制的字符串: 4E07 }

  {从 UniCode 编码到汉字}
  c := #19975;           {万}
  c := #$4E07;           {万}
  c := #$4e07;           {万}
  c := WideChar(19975);  {万}
  c := WideChar($4E07);  {万}
end;