ทำให้ App บน Windows เป็นสีขาว-ดำ

เนื่องจากว่าผมได้พยายามลองทำให้ Application บน Windows นั้นเปลี่ยนเป็นสีโทนขาว-ดำ เลยอยากจะแชร์สิ่งที่ได้ลองทำนะครับ (ถึงแม้ว่าผลของการ Implement นั้นยังไม่ถูกใจเท่าที่ควร)

ก่อนอื่นเลยผมขอเรียก app นี้ว่า Mourning App และเนื่องจากว่าต้องการทำสำหรับ Windows App ดังนั้นภาษาที่ผมใช้คือ C++ และ Win32 API ซึ่งตัว API ที่ใช้หลักๆคือ Magnification API ซึ่งเป็น Windows API ที่ปกติเอาไว้ทำพวก Tool ที่เป็นแว่นขยายต่างๆ

หลักการของ Mourning App ที่ผมทำมี 4 ขั้นตอน คือ

  1. หา Process ที่เราสนใจจะทำการ apply การทำภาพขาวดำก่อน

    API ที่ผมใช้ส่วนนี้คือ

    ::EnumProcesses ซึ่งทำให้เราได้จำนวน Process ที่กำลังรันอยู่ทั้งหมดมาพร้อมทั้ง Process ID ซึ่งเราจะใช้เอาไว้หาชื่อ Process ที่เราสนใจได้

  2. หา Window Handle (hwnd) ที่มันทำการแสดงผลอยู่ (visible) ของ Process นั้นๆ

    Code หลักๆที่ใช้ก็คือ  ::EnumWindows
    ซึ่งจากนั้นใน Callback ของ EnumWindowsProc นั้นจะได้ hwnd มาเรื่อยๆซึ่งผมจำการเช็ค

    if (!::IsWindow(hwnd) && !::IsWindowVisible(hwnd))
    return true;

  3. Render ทับตำแหน่ง application จริงๆด้วย Magnifier window พร้อมกับแปลงให้เป็นสีแบบ Gray Scale

    ส่วนนี้เป็นส่วนสำคัญที่สุด ซึ่งใช้ Magnification API โดยการสร้าง Window ด้วย Style : MS_CLIPAROUNDCURSOR

    m_hwndMag = CreateWindow(WC_MAGNIFIER, TEXT(“MagnifierWindow”),
    WS_CHILD | MS_CLIPAROUNDCURSOR | WS_VISIBLE

  4. ทำการ Refresh รูปบ่อยๆเพื่อให้ภาพเนียนที่สุดเวลา Application มีการ update หน้าจอ

    ส่วนนี้ไม่มีอะไรมากก็คือการตั้ง Timer เพื่อทำการ Refresh UI ครับแต่เราจะ Refresh เฉพาะ window ไม่ใช่ทั้งหน้าจอ Desktop

ตัวอย่างที่ได้ครับ

vscode
vscode in grayscale
chrome.png
Chrome เป็นสีเทา แต่ Edge ยังเป็นสีปกติ
ffx2.png
เกม FFX-2 ก็ทำให้ขาว-ดำ ได้นะครับ

ที่นี้มาดูผลที่ยังไม่น่าพอใจใน Implement ครั้งนี้ครับ

  1. ตัว render ภาพขาว-ดำนั้นเป็น Top Window ซึ่งทำให้ถ้ามี App ที่เปิดทับมันก็จะเป็นสีขาว-ดำด้วย
  2. ช้า เนื่องจากการ refresh นั้นบ่อยๆมีผลกับ Performance ทำให้ภาพมี delay บ้าง
  3. CPU ขึ้นตลอดเวลา 5% เนื่องจากต้อง query Process ตลอดเวลาในการเช็คว่ามี Window ของ Process ที่เราจะทำการ render ขาว-ดำ เปิดมาใหม่รึเปล่า

สุดท้ายนี้ ใครสนใจอยากดูตัวอย่างก็ Github เลยครับผม https://github.com/anurocha/mourning-win-app

เข้าสู่ C++ ยุคใหม่กับ Module System สำหรับ C++ 17/20

ไม่ยอมน้อยหน้าภาษา Modern เพราะหนึ่งใน Feature ที่มีการพูดถึงกันมากของมาตรฐานใหม่ของ C++ 17 ก็คือเรื่อง Module System (Link) ซึ่งเป็นแนวคิดทำให้ Library เป็น Module แบบจริงจัง โดยที่ทางกลุ่ม C++ Working Group ได้นำเสนอมานานแล้ว และมีแผนที่จะเอาเข้ามาเป็นส่วนหนึ่งของ C++ 17 แต่เหมือนว่าไม่น่าจะทัน C++ 17 แล้วครับ สรุปแล้วตอนนี้ Feature นี้อยู่ในขั้น Technical Specification ซึ่งน่าจะออกจริงใน C++ 20 (เลขข้างหลังเป็นเลขที่ เช่น 2017 หรือ 2020)

เป้าหมายของ Module System คือทำให้ C++ นั้นทำการ Compile ได้เร็วขึ้นและทำให้ Code นั้นมีการจัดการระดับ Component ได้ง่ายขึ้น เพราะปัจจุบัน #include นั้นใช้งานปนไปหมดทั้ง Headers, Inlines รวมทั้งบางทีมี Implemenation กันเลยทีเดียว

Microsoft นั้นได้ออก Preview สำหรับการทดลอง Module ใน Visual Studio 2015 Update 1+ มาลองดูกันเลยดีกว่า

ก่อนอื่นเลยครับ เนื่องจากว่า Visual Studio ในส่วนของ IDE นั้นยังไม่ Support ดังนั้นเราจะต้องทำการ Compile กับ Build ผ่าน Command Line นะครับ

สร้าง Module

ในการสร้าง Module นั้นให้เราสร้างไฟล์ใหม่มา ซึ่งโดยทั่วไปจะนิยมใช้ไฟล์ .ixx (ผมเดาว่ามาจาก Interface++)
เรามาสร้าง Module เอาไว้ Convert ค่าง่ายๆกัน

ไฟล์ converter.ixx

module converter;
export int CtoB(int x)
{
    return x + 543;
}

จาก code นี้จะเป็นการประกาศ Module ชื่อ converter ซึ่งมี function ‘CtoB’ ที่ทำการแปลง ค.ศ. ไป เป็น พ.ศ. ที่จะ export ออกไปให้ Code อื่นใช้

จากนั้นเราต้อง compile ด้วย commandline แบบนี้

cl /c /experimental:module converter.ixx

สิ่งที่ได้ก็คือไฟล์ converter.ifc กับ converter.obj

converter.png

เรียกใช้ Module

ที่นี้มาในส่วนของ Code หลักที่มี main entry point กันครับ ผมตั้งชื่อไฟล์ว่า main.cpp

ไฟล์ main.cpp

#include <iostream>
import converter;
int main()
{
 int year;
 std::cout << "Enter Year : ";
 std::cin >> year; 

 int bc = CtoB(year);
 std::cout << "Thai year is " << bc << std::endl;
 return 0;
}

Code ในส่วนนี้มีการเรียกใช้ Module ชื่อ ‘converter’ ด้วย keyword ที่ชื่อ import จากนั้นก็จะเรียกใช้ function ที่ชื่อ CtoB() ได้ทันทีเลยครับ

แน่นอนว่าเราต้อง compile ด้วย command line เช่นเคยโดยต้องระบุ converter.ifc เป็น parameter ของ module ที่จะเรียกใช้

cl /c /experimental:module /module:reference converter.ifc main.cpp

เมื่อรันเสร็จก็จะได้ main.obj มาครับ

main.png

ที่นี้จะเป็นว่าไม่มี .exe ให้เรา….สิ่งที่ต้องทำคือการสร้าง .exe ด้วย

link *.obj /OUT:main.exe

link.png

ทดสอบ

ลองรัน main.exe ที่ได้มาครับ ทำงานถูกต้องนะ 🙂

out.png

ลองด้วย Class

จากตัวอย่างข้างบนนั้นเป็นการสร้าง Module ด้วยการ export แค่ function แต่ถ้าเราอยากที่จะ  export Class ล่ะ เราก็ทำได้ครับ เช่น สร้าง Class  converter โดยมี method 2 ตัวให้เรียกใช้

module converter;
export namespace converterUtil
{
 class converter
 {
 public:
 int CtoB(int year)
 {
 return year + 543;
 }

 int CelsiusToFahrenheit(int c)
 {
 return (c * 1.8) + 32;
 }
 };
}

มาดูที่ main.cpp เราก็ทำการ import มาใช้และสร้าง Object ได้เลย เช่นใน ‘convt’ ตาม Code ด้านล่างนี้

#include <iostream>
import converter;
int main()
{
 converterUtil::converter convt;

 int year;
 std::cout << "Enter Year : ";
 std::cin >> year; 

 std::cout << "Thai year is " << convt.CtoB(year) << std::endl;

 int cel;
 std::cout << "Enter Temp in Celsius : ";
 std::cin >> cel; 
 std::cout << "Temp in Fahrenheit is " << convt.CelsiusToFahrenheit(cel) << std::endl;

 return 0;
}

ผลที่ได้ก็ Work ดีครับ!!

outex.png

สรุปแล้ว C++ Module น่าจะช่วยให้ C++ Developer ออกแบบและทำงานกับ Code ได้เป็นระเบียบเรียบร้อยขึ้น

และอีกอย่างคือจริงๆเท่าที่ผมลองในการสร้าง Module ถ้ามันมีใช้ header ตัวอื่นผมก็ยังทำให้มันเวิร์คไม่ได้นะ จึงต้องยกตัวอย่างแบบง่ายๆแบบนี้ครับ ซึ่งหวังว่าตัวจริงออกมาคงไม่วุ่นวายมากนะ

ณ. ตอนนี้เราก็มาเฝ้ารอ C++ 20 กันเลยกัย Module System!!

ปล. ดู Code ได้ที่ https://github.com/anurocha/cpp_module เลยครับผมอัพไว้ละ

เพิ่มคุณภาพของ Code ด้วย CppCheck

นอกจากการที่ทำ Feature ให้เสร็จตามกำหนดแล้วนั้น Developer ก็ควรจะต้องใส่ใจในคุณภาพของ Software กันด้วย ซึ่งหลายๆครั้งก็เป็นเรื่องที่ถูกละเลยและทำให้เกิด Bug แบบง่ายๆขึ้น

ทั้งนี้ทั้งนั้นในวงการเราก็มีเครื่องมือช่วยเหลือในการตรวจเช็คพวก Error พวกนี้ตั้งแต่การ Compile
ขั้นตอนหรือเครื่องมือนี้เรียกว่า Static Code Analysis 

สำหรับ C++ นั้นอย่างที่รู้ๆกันว่าเป็นภาษาที่มีประวัติยาวนานและเขียนได้หลาย Paradiam หรือปนกันทั้ง C และ C++ รวมทั้ง Framework ต่างๆที่ใช้ใน Software ซึ่งนี่แหละทำให้เกิด Error ได้ง่ายขึ้นไปอีก

พอดีผมเห็นข่าวว่าตัว CppCheck 1.75 เพิ่งจะ ออก (https://sourceforge.net/p/cppcheck/news/2016/08/cppcheck-175/) และผมไม่เคยใช้เจ้านี้เลยขอลองหน่อย

Cppcheck เป็นเครื่องมือที่ช่วยในการดักและแจ้งปัญหาเหล่านี้  ซึ่งเป็น Error ที่ไม่เกี่ยวกับ Compile นะครับ ยกตัวอย่างเช่น

  • Out of bounds
  • Memory leaks!
  • ตัวแปรที่ไม่ได้ initialize
  • Code ซ้ำๆ
  • และอื่นๆ

หลังจาก Install แล้วก็ลองรันโปรแกรมดู

cppcheck.png

ที่นี้เราลองเขียน Code เพื่อทดสอบ CppCheck กัน

// ConsoleApplication3_cpp.cpp
//

#include "stdafx.h"
#include 
#include 

using namespace std;

class Phone
{
public:
void Call() {}

private :
std::wstring _owner;
bool _enabled;
};

int main()
{
Phone *p = new Phone();
p = new Phone();
p->Call();
return 0;
}

Code นี้ผมวาง Error ไว้หลายตัวครับ เรามาลองให้ CppCheck ช่วยหาดีกว่า

cppcheck_1.png
ทำการเลือก Folder ของ Source Code ที่จะทำการ Scan หา Error

เลือกเสร็จ เจอ 3 ตัว! บรรทัดที่ 22 10 และ 23 (ตามคาด)

cppcheck_errorreport.png

 

ตัวอย่าง Error พวกนี้มาลองวิเคราะห์กัน

  1. Line 22: “Variable ‘p’ is reassigned a value before the old one has been used.”

    Phone *p = new Phone();
    p = new Phone();
    จะเห็นว่า pointer ‘p’ มีการชี้ไปที่ Object ที่สร้างจาก Class Phone แล้วไม่ได้ใช้เลยแต่ก็เอาไปชี้ที่ Object อีกตัว

  2. Line 10: “The class ‘Phone’ does not have a constructor.”

    class Phone
    {
    public:
    void Call() {}

    private :
    std::wstring _owner;
    bool _enabled;
    };
    จะเห็นว่า Class Phone เรานั้นไม่มี Constructor แต่เรามี private Members เช่น _owner กับ _enabled ซึ่งสำหรับ C++ นั้นพวก Members ควรจะทำการ Initialize ค่าก่อน เพราะ bool นี่อาจจะเป็น true/false ก็ไม่รู้ :S

  3. Line 23: “Memory leak: p”

    int main()
    {
    Phone *p = new Phone();
    p = new Phone();
    p->Call();
    return 0;
    }
    อันนี้ชัดเจนครับสำหรับ C++ Developer เพราะมีการ new ก็ต้องมีการ delete นะครับ เพราะไม่งั้น LEAK! จากตัวอย่างจบ function main แล้วเราไม่ได้ Delete ทาง CppCheck ก็เลยฟ้องซะเลย

จากตัวอย่างจะเห็นข้างต้นก็พอจะเห็นได้ว่า CppCheck นี้น่าจะช่วยเหลือเราได้ในการปรับปรุงใน Code ของเรามีคุณภาพมากขึ้นและ BUG แบบง่ายๆนั้นลดลง

“Quality is not an act, it is a habit.” – Aristotle
คุณภาพไม่ใช่หน้าที่ แต่เป็นอุปนิสัย – อริสโตเติล

C++ ภาษานี้ก็ยัง Powerful อยู่เช่นเดิม

c_0

ถ้ามีคนมาถามผมว่าอยากเริ่มเขียนโปรแกรมจะเริ่มจากอะไร ผมก็จะตอบว่า ลองเขียน Java, C# ดูซึ่งเป็น OOP เต็มรูปแบบ มีเครื่องมือครบ และมี Syntax ที่ดีมาก หรือว่าพวกภาษา Script เช่น JavaScript, Python ก็ได้ เพราะจะได้เป็นการหัดคิดแบบเป็น Logic และฝึกแก้ปัญหา

แต่ถ้า ถามว่าอยากเขียนโปรแกรมให้เก่งแบบมองภาพรวมของ Software Architecture ออกจะต้องยังไง
ผมก็จะตอบว่าเขียน C++ ดู

ถึงแม้ว่าภาษา C จะเกิดมาตั้งแต่ปี ค.ศ. 1972 และ C++ มาตอน 1983 แต่ภาษานี้ก็ยังคงความนิยมและคุ้มค่าต่อการศึกษาครับ

เพราะ…C++

  1. เป็นภาษาที่อยู่ระดับเกือบระดับต่ำสุดเป็นรองแค่ Machine Code กับ Assembly ทำให้เราต้องรู้ว่า CPU มันทำงานยังไง
  2. เป็นภาษาที่ใกล้ชิดกับ OS ทำให้เราต้องรู้ว่า OS แต่ละแบบทำงานยังไงมีส่วนประกอบอะไรบ้างสำหรับโปรแกรมหรือ App ของเรา เช่นการจัดการ Process, Thread, File System, Memory, การทำงานระหว่าง Process (IPC)
  3. ไม่ค่อยมี Tool หรือ Function สำเร็จรูปมาให้แบบ Built-In ทำให้การที่เราจะเขียนอะไรง่ายๆ เช่นจะเขียนแปลง String ก็ต้องเขียนเองเยอะ ซึ่งข้อดีคือทำให้เข้าใน Logic/Algorithm ได้ดีขึ้น และมีนิสัยไม่ขี้เกียจที่จะลงแรงเองถึงแม้งานที่ดูเหมือนง่ายอาจจะต้องเขียนกัน 20-30 บรรทัด
  4. ไม่มี Memory Management ที่ฉลาดๆ เราที่จะเขียนก็ต้องฉลาดที่จะใช้เอง ต้องรู้ว่า Memory เก็บยังไงหลังจากที่ทำการ Allocate แล้ว และต้องรู้ว่าจะคืน Memory ให้ระบบตอนไหน
  5. เป็นภาษาที่ถูกต่อยอดไปเป็นภาษาสมัยใหม่หลายๆภาษา เช่น Java, C#, Objective-C, Swift, PHP, Python, Perl, Ruby, JavaScript และอื่นๆอีกมาก ทำให้เราสามารถไปศึกษาภาษาพวกนี้ได้เร็วขึ้น(จริงๆนะ)
    เปรียบเทียบกับทำให้เหมือนเรารู้ภาษาละตินซึ่งเป็นรากฐานของภาษาในยุโรปเกือบทั้งหมด!
  6. ทำให้รู้กระบวนการของการ Compile โปรแกรมตั้งแต่ เขียน Code ไปจนได้ไฟล์ Executable ออกมา
  7. เข้าใจการทำงานของ Framework หลายๆอย่างในปัจจุบัน เช่น OS, Web Browser, .NET Framework หรือ JVM รวมทั้ง Game Engine ต่างๆ และยังใช้เขียนต่อกับ Hardware ด้วย
  8. ส่วนมากจะเป็นสะพานเชื่อมการทำงานระหว่าง Technology เช่นเขียน .NET app ให้คุยกับ Web
  9. Performance ถึงแม้ว่าทุกวันนี้ CPU เราจะแรง แต่ถ้าต้องการรีด CPU ทุก clock cycle การใช้ C++ ก็ช่วยได้นะครับ
  10. Debug ได้ถึง Memory รวมทั้งสามารถ Deassembly Code มาดูเพื่อทำ Reverse Engineer ได้ ถ้าเราเก่งพอ :p
  11. เขียนได้หลาย Paradiam เช่น Imperative, Object-Oriented, Generic Programming (และทำให้ Code มั่วดีด้วยครับถ้าเขียนบนกันทุก Paradiam 555)
  12. ที่สำคัญ ภาษา C++ นั้นยังมีการพัฒนาอยู่เสมอซึ่ง version หลังๆก็คือ C++11/C++14 และที่กำลังจะมาคือ C++17 (เลขข้างหลังคือเลขปี ค.ศ.ที่จะออก) ซึ่งสิ่งที่เพิ่มเข้ามาทำให้เขียน Code ได้ง่ายขึ้น เช่นเดียวกับภาษายุคใหม่แหละครับ

 

C++ is still ROCK (as always)!

ปล.

  • บทความนี้ความเห็นส่วนตัวนะครับ 🙂
  • C++ เป็นภาษาแรกที่ผมอยากเขียนหลังจากที่ผมรู้จักคอมพิวเตอร์ ตอน ม.ปลาย (เพราะอยากเขียนเกม) แต่ไม่สำเร็จเพราะเข้าไม่ถึงผมเลยหนีไปเขียนเวป PHP, C#, Java ตอนเรียนมหาวิทยาลัย
  • C++ เป็นภาษาที่ใช้ในโปรเจคแรกของชีวิตการทำงาน Developer ของผม