Intro to COM Part 1 - Interface Based Programming

Jika Anda menjadi programmer di platform Microsoft, tentunya Anda akan bertemu dengan makhluk bernama COM (Component Object Model). COM digunakan dari membuat addins di Office sampai membuat game dengan DirectX.

 

Tentunya Anda pernah melihat kode sampel dengan tulisan “CoCreateInstance” bukan?

 

Terkadang ada library yg belum ada padanannya di .Net, tapi ada versi COM-nya. Nah, oleh karena itu marilah kita belajar COM daripada menghindarinya.

 

Untuk Part One ini, saya akan membahas tulang punggung COM, yaitu konsep interface.

 

Pertama, buka dokumentasi MSDN, dan cari info tentang methods yg ada di class CWnd (bagian dari C++ MFC Library). Anda akan melihat seperti berikut:

 COMPart1-01

Class CWnd adalah ibu dari controls, frames, views dan elemen window lainnya. Dalam dokumentasi MSDN terlihat bahwa methods CWnd dipartisi berdasarkan fungsi; contoh ada Drag-n-Drop Functions dan Data-Binding Functions.

 

Sekarang coba buat sebuah aplikasi MFC baru di Visual Studio. Kemudian buatlah sebuah objek bertipe CWnd  dan lihat berapa banyak method yang ada di instance ini setelah Anda ketik . (dot operator)!

COMPart1-02

Class CWnd hanya memiliki satu public interface, dan interface ini memikul terlalu banyak tanggung jawab. Untuk bikin menu, pake interface ini. Untuk akses clipboard pake interface ini.

Padahal seperti ditunjukkan oleh MSDN Library, satu public interface yang berisi ratusan methods ini dapat dikelompokkan berdasarkan fungsi.

 

So, bayangkan jika CWnd meng-ekspos beberapa interface seperti IMenu dan IClipboard. Kita akan menulis kode seperti berikut:

 

bool result = false;

IMenu *pMenu = NULL;

IClipboard *pClip = NULL;

 

// Activate the CWnd object

CreateCWndObj();

 

// Support IMenu kagak?

result = GetInterfaceFromCWnd(IMENU, (void**)&pMenu);

if (result) {

   pMenu->Draw("Selamat datang di dunia interface-based programming");

}

 

// Support IClipboard?

result = GetInterfaceFromCWnd(ICLIPBOARD, (void**)&pClip);

if (result) {

   pClip->Copy();

}

 

Kodenya memang lebih panjang, tapi jika kita ketik pClip-> maka Intellisense Visual Studio hanya akan menampilkan method yg berhubungan dengan Clipboard, seperti Copy dan Paste. Kita tidak akan dapat method seperti ShowCaret() dan lainnya yang tidak berhubungan dengan interface IClipboard.

 

Sebuah class yang hanya memiliki satu interface tapi ratusan methods seperti CWnd dapat mengintimidasi pengguna class tersebut. Ketika user menggunakan IClipboard, user hanya bekerja dengan satu behavior dari class tersebut.

 

Sebelum melangkah ke COM interfaces, sementara ini kita definisikan interface sebagai berikut (dlm bhs Inggris agar tidak hilang maknany):

 

An interface is a collection of a semantically related functions, which describe a single and unique behavior that may be supported by a class.

 

Diagram Interface

Notasi interface digambar seperti “lollipop”. Untuk contoh custom CWnd kita diatas, berikut gambarnya:

COMPart1-03 

Gambar seperti diatas akan banyak Anda jumpai di literatur tentang COM. COM disebut sebagai interface-based programming paradigm. Semua hal di COM berpijak pada creation dan implementation tentang interfaces.

 

Interface terasa sama seperti public interface sebuah standar C++/C# class, bedanya ada 2:

-         interface tidak berisi kode implementasi

-         interface tidak pernah mendefinisikan state

 

Enkapsulasi yg lebih Dalem

Hal paling penting dari interface-based programming adalah pengguna object tidak boleh mengakses fungsi-fungsi yang tersedia dari object instance, melainkan dari interface yang di-support.

 

Contohnya adalah kode berikut:

 

interface IDraw

{

   virtual void Draw() = 0;

}

 

interface ITransform

{

   virtual void Rotate(float degrees) = 0;

   virtual void Scale(float size) = 0;

}

 

class Lingkaran : public IDraw,

                  public ITransform

{

public:

   // IDraw

   void Draw();

 

   // ITransform

   void Rotate(float degrees);

   void Scale(float size);

 

private:

   // state untuk implementasi interface

}

 

Ketika di-compile, C++ compiler akan menghasilkan layout virtual table berikut:

COMPart1-04 

Terus dalemnya enkapsulasi dimana? Jadi ketika kita mendapatkan handle ke interface IDraw (IDraw_VirtualPointer), itu sebenarnya mengarah ke virtual table IDraw (yg hanya berisi Draw). Kita tidak bisa mengakses fungsi Rotate() walaupun Rotate() terdefinisikan di class yg sama!

 

Interface Versioning

Setelah interface di-publish, tidak baik untuk mengubah ubah interface tersebut. Lantas bagaimana meng-extend sebuah interface? Dengan sebuah teknik bernama interface inheritance.

 

Contohnya jika kita ingin meng-extend IDraw dari kode di atas, adalah seperti berikut:

interface IDraw2 : public IDraw

{

   virtual void DrawKeMemory() = 0;

}

 

// Setelah 6 bulan, kita ingin

// draw ke file

interface IDraw3 : public IDraw2

{

   virtual void DrawKeFile() = 0;

}

 

Ini akan menghasilkan layout seperti berikut:

COMPart1-05 

Jadi kalo kita ingin menggunakan class yg implement semua fungsi Draw() yang terbaru, kodenya menjadi seperti ini:

class Lingkaran : public IDraw3

{

   // IDraw3 = IDraw + IDraw2 + IDraw3

   void Draw();

   void DrawKeMemory();

   void DrawKeFile();

}

 

// Kode ini salah

class Lingkar : public IDraw,

                public IDraw2,

                public IDraw3

{

   // . . .

}

 

Konklusi dan Sample Code

Interface-based programming bisa dikatakan sebagai refinement dari OOP klasik, dan fondasi dari awal belajar COM. Logically, interface adalah koleksi beberapa fungsi yg mendeskripsikan satu behavior. Physically, interface adalah sebuah set terdiri dari bebera pure virtual functions.

 

Berikut sample code untuk menjelaskan prinsip interface-based programming yang telah dibahas:

 

// main.cpp

#include <iostream>

using namespace std;

 

// ada definisi interface disini

#include <windows.h>

 

interface IDraw

{

   virtual void Draw() = 0;

};

 

interface ITransform

{

   virtual void Rotate(float degrees) = 0;

   virtual void Scale(float size) = 0;

};

 

class Kotak : public IDraw,

              public ITransform

{

public:

   Kotak() {}

   virtual ~Kotak() {}

 

   // IDraw

   virtual void Draw() {

      cout << "Kotak::Draw() dipanggil"

           << endl;

   }

 

   // ITransform

   virtual void Rotate(float degrees) {

      cout << "Rotasi dengan derajat "

           << degrees

           << endl;

   }

 

   virtual void Scale(float size) {

      cout << "Resize object sebesar "

           << size << " unit"

           << endl;

   }

};

 

// Kotak API

// ini semua tersedia oleh COM

// jika kita membuat COM library

Kotak *pKotak;

 

void CreateKotak() {

   pKotak = new Kotak();

}

 

void DestroyKotak() {

   delete pKotak;

}

 

enum INTERFACEID {

   IDRAW = 0,

   ITRANSFORM = 1,

   IMENU = 2,

};

 

bool GetInterfaceFromKotak(INTERFACEID id, void** ifacePtr) {

   if (pKotak == NULL) {

      cout << "Lupa bikin Kotak nih yee..." << endl;

      return false;

   }

   if (id == IDRAW) {

      *ifacePtr = (IDraw*) pKotak;

      return true;

   }

   if (id == ITRANSFORM) {

      *ifacePtr = (ITransform*) pKotak;

      return true;

   }

 

   *ifacePtr = NULL;

   cout << "Kotak tidak support ID: " << id << endl;

   return false;

}

 

int main()

{

   bool result = false;

   IDraw *pDraw = NULL;

   ITransform *pTrans = NULL;

 

   // Activate Kotak

   CreateKotak();

 

   // Bisa dapet IDraw interface nggak?

   result = GetInterfaceFromKotak(IDRAW, (void**) &pDraw);

   if (result) {

      pDraw->Draw();

   }

 

   // ITransform bisa?

   result = GetInterfaceFromKotak(ITRANSFORM, (void**) &pTrans);

   if (result) {

      pTrans->Rotate(90);

      pTrans->Scale(2);

   }

 

   result = GetInterfaceFromKotak(IMENU, (void**) &pTrans);

 

   // Destroy

   DestroyKotak();

 

   return 0;

}

 

Referensi:

Developer's Workshop to COM and ATL 3.0 , Andrew W. Troelsen, Wordware.

Share this post: | | | |
Published Thursday, February 01, 2007 6:28 AM by zeddy

Comments

# re: Intro to COM Part 1 - Interface Based Programming

Thursday, February 01, 2007 4:21 PM by csharpindonesia

Koreksi dikit

"Kita tidak bisa mengakses fungsi Rotate() walaupun Rotate() terdefinisikan di class yg sama!"

Seharusnya

"Kita tidak bisa mengakses fungsi Rotate() walaupun Scale() terdefinisikan di class yg sama!"

BTW

"Terkadang ada library yg belum ada padanannya di .Net, tapi ada versi COM-nya"

Contohnya apa ya? :)

# re: Intro to COM Part 1 - Interface Based Programming

Wednesday, February 07, 2007 11:34 AM by edward
?? bukannya statement "Kita tidak bisa mengakses fungsi Rotate() walaupun Rotate() terdefinisikan di class yg sama!" emank bener? Basically, when a COM-client / user got the handle to the IDraw interface via IUnknown method QueryInterface() which in a simple matter says "did u support this interface?" it get the handle to the interface which contains a vTable where the pointers to the functions (the old form of C# delegates) defined by the interface lives in. Jadi jika kita hanya mendapatkan handle ke interface IDraw, kita hanya bisa mengakses fungsi yang didefine oleh IDraw (which in this case it only defines one 1 function, Draw(). The functions Rotate() and Scale() belongs to ITransform). Hal itu juga berlaku buat ITransform, and so on. Banyak lib yang blom ada padananny di .net, tapi ada versi COMnya. Cthnya lib buat vba apps, kita mesti pake interop buat commmunicate dgn office, but skrg ada vsto, isn't it? =( Contoh laen buat communicate dengan Indexing service windows, mesti pake IFilter, which was COM-based. CMIIW

# Intro to COM Part 2 - IUnknown, CoCreateInstance, CLSID

Tuesday, February 20, 2007 6:33 PM by BloggiZ - Blogging by Z

OK, sekarang kita akan terjun ke dunia COM sekarang. Bagi yg masih belum mengerti kenapa &ldquo;Kita

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above:
Powered by Community Server (Commercial Edition), by Telligent Systems