Tags:
Node Thumbnail

หลังจากได้รู้จักกับ Intel AppUp Center รวมถึงได้เห็นหน้าค่าตาของ Intel Atom Developer Program SDK สำหรับแอพลิเคชันที่จะเข้าไปทำตลาดกันบ้างแล้ว คราวนี้เราจะมาลองสร้าง/ปรับปรุงแอพลิเคชันเพื่อเตรียมลุยใน AppUp กัน โดยในบทความนี้จะเริ่มจากภาษา C/C++ กันก่อน เพราะตัว SDK รองรับมาตั้งแต่แรก ส่วนภาษาอื่นๆ นั้นแนวคิดจะคงเดิมแต่อาจจะต้องใช้ตัว binding ครับ

เตรียมวัตถุดิบ

  1. โอนสัญชาติเป็นชาวอเมริกัน โดยเปิดหน้าต่าง Region and Language จาก Control Panel แล้วแก้ไขค่าต่อไปนี้

    • Format: English (United States)
    • Current location: United States
    • Current language for non-Unicode programs: English (United States)
  2. ติดตั้ง Intel Atom Developer Program SDK
  3. ติดตั้ง Visual C++ 2008 (ใช้รุ่น 2010 ได้ แต่ต้องติดตั้งรุ่น 2008 ไว้ด้วย เนื่องจาก SDK พัฒนาโดยอ้างอิง C Runtime รุ่น 9.0)

เตรียมโปรเจกต์

เพื่อให้โปรเจกต์ของเราเรียกใช้ SDK ได้ เราจะต้องตั้งค่าเล็กน้อยเพื่อให้โปรเจกต์ของเรารู้จักไฟล์ header และไลบรารีก่อน

สำหรับ Visual C++ 2008

  1. เลือกเมนู Projects > [ชื่อโปรเจกต์] Properties...
  2. ในหัวข้อ Configuration Properties > General กำหนดค่า Common Language Runtime support: Common Langauge Runtime Support (/clr)
  3. ในหัวข้อ Configuration Properties > C/C++ กำหนดค่า Additional Include Directories: [ที่อยู่ SDK ของคุณ]\include (สำหรับ SDK 1.0 ขึ้นไป เปลี่ยนเป็น [ที่อยู่ SDK ของคุณ]\Cpp\include)
  4. ในหัวข้อ Configuration Properties > Linker กำหนดค่า Additional Library Directories: [ที่อยู่ SDK ของคุณ]\library (สำหรับ SDK 1.0 ขึ้นไป เปลี่ยนเป็น [ที่อยู่ SDK ของคุณ]\Cpp\lib)
  5. ในหัวข้อ Configuration Properties > Linker > Input กำหนดค่า
    • Additional Dependencies:

      • สำหรับโหมด debug: adpcored.lib adpcppfd.lib Psapi.lib Advapi32.lib shlwapi.lib
      • สำหรับโหมด release: adpcore.lib adpcppf.lib Psapi.lib Advapi32.lib shlwapi.lib
    • Force symbol references: __DllMainCRTStartup@12
สำหรับ Visual C++ 2010
  1. เลือกเมนู Project > [ชื่อโปรเจกต์] Properties...
  2. ในหัวข้อ Configuration Properties > General จากหัวข้อด้านซ้าย กำหนดค่า
    • Platform Toolset: v90
    • Common Language Runtime support: Common Langauge Runtime Support (/clr)
  3. ในหัวข้อ Configuration Properties > VC++ Directories แล้วเพิ่มที่อยู่ต่อไปนี้เข้าไป
    • Executable Directories: เพิ่ม [ที่อยู่ SDK ของคุณ]\bin (สำหรับ SDK 1.0 ขึ้นไป เปลี่ยนเป็น [ที่อยู่ SDK ของคุณ]\Cpp\bin)
    • Include Directories เเพิ่ม [ที่อยู่ SDK ของคุณ]\include (สำหรับ SDK 1.0 ขึ้นไป เปลี่ยนเป็น [ที่อยู่ SDK ของคุณ]\Cpp\include)
    • Library Directories เพิ่ม [ที่อยู่ SDK ของคุณ]\lib [ที่อยู่ SDK ของคุณ]\Cpp\lib)
  4. ในหัวข้อ Configuration Properties > Linker > Input กำหนดค่าเช่นเดียวกับ Visual C++ 2008 แต่คั่นแต่ละชื่อไฟล์ด้วย semi-colon
  5. ในกรณีที่เป็นโปรเจกต์แบบ Windows Form ซึ่งต้องใช้ .NET Framework นั้น จำเป็นต้องเปลี่ยนโปรเจกต์ให้ทำงานบน .NET Framework รุ่น 3.5 หรือต่ำกว่า ทำได้โดย
    • ปิดโปรเจกต์นั้นก่อน
    • เปิดไฟล์โปรเจกต์ (นามสกุล .vcxproj) ด้วยโปรแกรมแก้ไขไฟล์ข้อความ
    • แก้ไขค่าในแท็ก TargetFrameworkVersion ให้ตรงกับรุ่นที่ต้องการ

เริ่มต้น

สำหรับภาษา C แน่นอนว่าเราต้องเรียกใช้จากฟังก์ชันต่างๆ ที่ SDK เตรียมไว้ให้เท่านั้น แต่กับภาษา C++ เรามีให้เลือกสองวิธีหลักๆ คือ

  • สร้างวัตถุจากคลาส Application ขึ้นมาใช้โดยตรง
  • สร้างคลาสสืบทอดจากคลาส Application เพื่อใส่การทำงานของแอพลิเคชันของเราลงไปก่อน แล้วค่อยสร้างคลาสนั้นขึ้นมาใช้

เนื่องจากที่อื่นจะแสดงวิธีแรกให้เห็นกันเป็นส่วนมาก วันนี้เราจะแนะนำโดยทำวิธีหลังกันครับ

ก่อนอื่นเรามาสร้างคลาสแอพลิเคชันของเรากัน

alt="โครงสร้างของโปรเจกต์ตัวอย่าง"

ADPApplication.h

{syntaxhighlighter brush: cpp}

include <vcclr.h>

include "stdafx.h"

include "adpcppf.h"

include "MainForm.h"

using namespace HelloAppUp;

// Define your application ID, or use ADP_DEBUG_APPLICATIONID in testing.
const com::intel::adp::ApplicationId adp_app_id = ADP_DEBUG_APPLICATIONID;

class ADPApplication: public com::intel::adp::Application {

public:

    // Constructor
    ADPApplication(): com::intel::adp::Application(adp_app_id) {
        // Don't remove this pair of bracket, to pass the compilation.
    }

    int run() {
        System::Windows::Forms::Application::Run(gcnew MainForm());
        return 0;
    }

};
{/syntaxhighlighter}

เริ่มต้นจากการสร้างคลาสสำหรับแอพลิเคชันของเรา ซึ่งสืบทอดมาจากคลาส Application ใน SDK เนื่องจากใน Windows Form ก็มีคลาสชื่อ Application เหมือนกัน เพื่อไม่ให้สับสน เราจึงต้องระบุ namespace ของคลาสกำกับไว้ด้วยเมื่อเรียกใช้

ในส่วนของ constructor ของคลาส Application นั้นจะให้เราระบุหมายเลขแอพลิเคชันของเรา (Application ID) เป็นอาร์กิวเมนต์ด้วย ซึ่งเราจะได้จากการลงทะเบียนแอพลิเคชันในระบบ แต่ในช่วงพัฒนาแอพลิเคชัน เราสามารถใช้หมายเลขพิเศษ ADP_DEBUG_APPLICATIONID ไปก่อนได้

ส่วนฟังก์ชัน run ไม่ใช่ฟังก์ชันบังคับจาก SDK นะครับ ผมสร้างเองเพื่อใช้รันแอพลิเคชัน ซึ่งก็คัดลอกเอาซอร์สโค้ดส่วนเปิดหน้าต่างแอพลิเคชันจากโปรเจกต์ที่สร้างขึ้นตอนแรกมาใช้เท่านั้นเอง

การตรวจสอบสิทธิ์การรันแอพลิเคชันของผู้ใช้

แน่นอนว่าเราไม่อยากให้ใครคัดลอกแอพลิเคชันของเราไปใช้ฟรีๆ ดังนั้น SDK จะช่วยเราตรวจสอบผู้ใช้ที่เปิดแอพลิเคชันว่า ซื้อแอพลิเคชันของเรามาถูกต้อง และยังไม่หมดอายุการใช้งาน การทำงานส่วนนี้อยู่ใน constructor ของคลาส Application โดยจะตรวจสอบสิทธิ์ของผู้ใช้สำหรับแอพลิเคชันที่มีหมายเลขตามที่เราระบุลงไปเป็นอาร์กิวเมนต์ใน constructor นั่นเอง ยกเว้นสำหรับหมายเลขพิเศษ ADP_DEBUG_APPLICATIONID นั้น ส่วนของ SDK จะปล่อยผ่านให้ เพื่อให้เราใช้ทดสอบได้

หากผู้ใช้ไม่ผ่านการตรวจสอบ ไม่ว่าจะเกิดจากผู้ใช้ยังไม่ได้ซื้อแอพลิเคชันของเรา, แอพลิเคชันหมดอายุแล้ว, เปิดแอพลิเคชันนี้ไว้แล้ว, หรือไม่สามารถติดต่อบริการ (service) ตรวจสอบสิทธิ์ได้ จะโยน exception ออกมาให้ ดังนั้นเมื่อเรานำคลาสเมื่อสักครู่นี้ไปใช้ เราจะต้องดักจับ exception นี้ด้วย

เราไปดูไฟล์ที่มีฟังก์ชัน main ซึ่งจะเรียกใช้คลาส ADPApplication ที่เราสร้างไว้ครับ

HelloAppUp.cpp

{syntaxhighlighter brush: cpp}
// HelloAppUp.cpp : main project file.

include "stdafx.h"

include "ADPApplication.h"

ADPApplication *adp_app = NULL;

using namespace HelloAppUp;

[STAThreadAttribute]
int main(array ^args) {
// Enabling Windows XP visual effects before any controls are created
System::Windows::Forms::Application::EnableVisualStyles();
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault(false);

// Try to authen.
try {
    adp_app = new ADPApplication();
}
catch (AdpException& ex) {
    // Authentication failed. Show the error message, then exit.
    String^ errorMessage = gcnew String(ex.message());
    MessageBox::Show(errorMessage, "Authorization Problems",
        System::Windows::Forms::MessageBoxButtons::OK,
        System::Windows::Forms::MessageBoxIcon::Error);

    if (adp_app != NULL) {
        delete adp_app;
    }

    exit(-1);
}

// Authentication passed. We can run the application now.
int returnCode = adp_app->run();

// Don't forget to clear the Application object from the memory.
if (adp_app != NULL) {
    delete adp_app;
}

return returnCode;

}
{/syntaxhighlighter}

ส่วนหลักของโปรแกรมก็พยายามสร้างวัตถุจากคลาสแอพลิเคชันของเราขึ้นมา หากไม่มีสิทธิ์รันแอพลิเคชันก็จะแสดงหน้าต่างแสดงข้อผิดพลาดขึ้นมา และจบโปรแกรมทันที

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

การทดสอบแอพลิเคชัน

ตอนนี้แอพลิเคชันของเราก็รันได้ และพร้อมที่จะทดสอบเบื้องต้นแล้ว โดยในการทดสอบนั้น เราจะต้องเปิดการทำงานของบริการ ATDS เสียก่อน โดยเรียกใช้ได้จาก Start Menu

สำหรับเครื่องที่ติดตั้ง Intel AppUp Center ไว้ด้วย จะต้องปิดโปรเซสบริการของ Intel AppUp Center (serviceManager.exe) ก่อนนะครับ

เมื่อเปิด ATDS แล้วเปิดโปรแกรมของเราขึ้นทดสอบ หน้าต่างคอนโซลของ ATDS จะแสดงข้อมูลการติดต่อกับแอพลิเคชันของเราให้เห็น

alt="หน้าต่างคอนโซลของ ATDS"

การบันทึกสถิติและข้อผิดพลาดของแอพลิเคชัน

อีกส่วนหนึ่งที่ SDK จะช่วยเหลือเราคือการบันทึกสถิติการใช้งานของผู้ใช้ (ในรุ่นเบต้านี้จะบันทึกไว้เฉพาะระยะเวลาที่ผู้ใช้ใช้แอพลิเคชัน) และข้อผิดพลาดต่างๆ ของแอพลิเคชัน โดยข้อมูลเหล่านี้จะถูกบันทึกไว้ในเครื่องของผู้ใช้ก่อน จากนั้นบริการของ AppUp จะจัดการส่งข้อมูลไปที่ Developer Portal เพื่อรวบรวมข้อมูลมาแสดงให้เรารู้ทางแดชบอร์ดต่อไป

เราจะกลับไปที่คลาส ADPApplication ของเราอีกครั้งเพื่อเพิ่มเติมคำสั่งในส่วนนี้กันครับ

ADPApplication.h (เพิ่มเติม)

{syntaxhighlighter brush: cpp}

include <vcclr.h>

include "stdafx.h"

include "adpcppf.h"

include "MainForm.h"

using namespace HelloAppUp;

// Define your application ID, or use ADP_DEBUG_APPLICATIONID in testing.
const com::intel::adp::ApplicationId adp_app_id = ADP_DEBUG_APPLICATIONID;

class ADPApplication: public com::intel::adp::Application {

public:

    // Constructor
    ADPApplication(): com::intel::adp::Application(adp_app_id) {
        // Don't remove this pair of bracket, to pass the compilation.
    }

    int run() {
        try {
            // Our normal source code of the application goes here.
            System::Windows::Forms::Application::Run(gcnew MainForm());
            return 0;
        }
        catch (Exception^ e) {
            // Unhandled exception is caughted. We'll report it, and exit the application.
            ADP_RET_CODE reportResult = reportException(e);
            String^ message;

            if (reportResult == ADP_SUCCESS) {
                message = "Unexpected error occurs. It'll be reported to the developers.";
            }
            else {
                message = "Unexpected error occurs, and it can't be reported.";
            }

            MessageBox::Show(message,  "Unexpected Error",
                    System::Windows::Forms::MessageBoxButtons::OK,
                    System::Windows::Forms::MessageBoxIcon::Error);

            return -1;
        }
    }

private:

    ADP_RET_CODE reportException(Exception^ e) {
        // Collect general information.
        // Sending stack trace as errorData, and useing __LINE__ are not good examples.
        wchar_t* moduleName = toWchar(e->Source);
        wchar_t* message = toWchar(e->Message);
        wchar_t* category = L"Exception";
        wchar_t* errorData = toWchar(e->StackTrace);
        long line = __LINE__;

        // Prepare the custom fields.
        ADP_CrashReportField customFields[1];
        customFields[0].name = L"ExceptionType";
        customFields[0].value = toWchar(e->GetType()->FullName);

        // Report.
        return pClientProxy->ReportCrash(moduleName, message, category, line,
            errorData, customFields, 1);
    }

     static wchar_t* toWchar(String^ str) {
        // Just convert the String^ to wchar_t*
        pin_ptr<const wchar_t> result = PtrToStringChars(str);
        return (wchar_t*)result;
    }

};
{/syntaxhighlighter}

เนื่องจากเราก็ไม่รู้เหมือนกันว่าแอพลิเคชันของเราจะเกิดข้อผิดพลาดตรงไหน ดังนั้นจุดยุทธศาสตร์หลักที่เราจะดักไว้ ก็คือดักข้อผิดพลาดครอบการทำงานของทั้งแอพลิเคชันเลยครับ จากนั้นเมื่อเกิดข้อผิดพลาดก็ใช้เมธอด reportCrash ของ pClientProxy เพื่อรายงาน ก่อนจะปิดแอพลิเคชันลงอย่างสวยงามด้วยหน้าต่างแจ้งผู้ใช้ของเรา

ข้อมูลเบื้องต้นที่เราส่งได้ก็คือ ชื่อโมดูลที่เกิดปัญหา, ข้อความ, หมวดหมู่ของปัญหา, บรรทัดที่เกิดปัญหา รวมถึงใส่ฟิลด์ของเราเองเพิ่มได้ นอกจากนี้ เรายังสามารถส่ง stack trace ไปได้ด้วย โดยต้องลงแรงเพิ่มอีกสักหน่อย แต่เราจะไม่พูดถึงในบทความนี้ และใช้วิธีที่ง่ายๆ คือส่งไปในฟิลด์ errorData แทน

ในส่วนของ ATDS เมื่อได้รับรายงานความผิดพลาดแล้ว ก็จะแจ้งตำแหน่งที่เก็บรายละเอียดไว้ ให้เราไปดูข้อมูลความผิดพลาดที่เรารายงานเข้าไปได้

alt="การแสดงผลจาก ATDS เมื่อรายงานข้อผิดพลาด"

alt="ตัวอย่างเนื้อหาไฟล์บันทึกข้อมูลความผิดพลาด"

บทสรุป

จากที่ผ่านมาทั้งหมด สังเกตว่าผมไม่ได้พูดถึงตัวแอพลิเคชันเลยแม้แต่น้อย เพราะการพัฒนาแอพลิเคชันสำหรับออกสู่ตลาด Intel AppUp Center นั้น เราไม่จำเป็นต้องแก้ไขหรือเขียนโปรแกรมสำหรับ AppUp โดยเฉพาะ เพียงแต่เติมเต็มส่วนต่างๆ เพื่อเอาประสิทธิภาพในการซื้อขายแอพลิเคชันผ่าน AppUp มาใช้เท่านั้น ซึ่งดูจะง่ายกว่าการเตรียมระบบยืนยันต่างๆ เวลาทำแอพลิเคชันขายเองมากเลยทีเดียว

หมายเหตุ

  • ตัวอย่างนี้ไม่แยกการประกาศคลาสในไฟล์เฮดเดอร์ และเขียนซอร์สโค้ดการทำงานในไฟล์ซอร์สโค้ดแยกต่างหาก เพื่อความสะดวกในการอธิบาย
  • การดักจับข้อผิดพลาดในตัวอย่างอาจดักจับข้อผิดพลาดของโปรแกรมที่ทำงานแบบมัลติเธรดไม่ได้

เพิ่มเติม

  • สำหรับใครที่จะลองพัฒนา แนะนำแหล่งข้อมูลและชุมชนนักพัฒนาหลักๆ ที่เว็บไซต์ของ Intel Atom Developer Program ครับ
  • ส่วนตัวอย่างแอพลิเคชันในบทความนี้ดาวน์โหลดได้ที่นี่ครับ
  • ในตอนนี้เองประเทศไทยมีนักพัฒนาร่วมในโครงการ IADP เป็นอันดับที่ 15 ของโลก และอันดับ 5 ของเอเชียรองจาก อินเดีย, จีน, ปากีสถาน, และมาเลเซีย ครับ
  • ใบ้ๆ ว่าเร็วๆ นี้เราจะมีโครงการแข่งซอฟต์แวร์ภายใน Blognone นะครับ ถึงตอนนี้อาจจะลองหาลู่ทางพัฒนาไว้ได้เลย

ข่าวและบทความหมวด - Intel AppUp Center ได้รับการสนับสนุนจากอินเทล เพื่อประชาสัมพันธ์โครงการ Intel Atom Developer Program ให้กับนักพัฒนาในประเทศไทย

Get latest news from Blognone

Comments

By: anu
Contributor
on 5 September 2010 - 16:45 #206830

พวก VS Express เวอร์ชั่นจะใช้ได้รึเปล่าครับ

By: champjss
ContributorAndroidUbuntuWindows
on 6 September 2010 - 01:42 #206897 Reply to:206830
champjss's picture

ได้นะครับ ที่ผมใช้นี่ก็รุ่น express เหมือนกัน