COM DLL Akses MySQL – Bagian 4: Membuat Operasi CRUD Untuk Tabel Mahasiswa

Tulisan ini merupakan bagian dari panduan membuat COM DLL (ATL) di Visual Studio 2010 yang mengakses MySQL atas request Albert Antonius:

Pada artikel sebelumnya, kamu sudah membuat operasi insert ke tabel melalui Connector/C++ di COM ATL.  Kali ini, kamu akan membuat sebuah proyek baru yang menyediakan operasi CRUD (Create, Read, Update, Delete) untuk tabel Mahasiswa tersebut.  Kamu juga akan memakai cara yang lebih OOP dibandingkan dengan cara kemarin.  “Apa bedanya? Yang penting ‘kan sama2 bisa jalan?”  tanyamu.   Meningkatkan kualitas kode program, mempermudah perawatan dan perubahan, memudahkan seseorang memahami kode program.

Seperti apa rancangan program yang akan kamu buat?  Kata-kata akan sulit menjelaskannya, jadi lebih baik kamu melihat Component Diagram-nya sendiri:

Component Diagram

Component Diagram

Pada diagram di atas, terlihat bahwa DLL kita mengandung dua class, masing-masing dengan ProgID Jocki.Mahasiswa dan Jocki.MahasiswaService.  PHP akan berinteraksi dengan Jocki.MahasiswaService melalui interface IDispatch.   “Lalu buat apa Jocki.MahasiswaService menyediakan bulat-bulat (baca: provided interface) bernama IMahasiswaService yang tidak pernah dipakai?” kamu pasti bertanya demikian.  Pada komunikasi yang ideal, kamu akan memakai interface ini.  Sayangnya, bila kamu ingin memakai COM di bahasa seperti VB & PHP, maka kamu harus menyediakan IDispatch, karena itulah satu-satunya harapan mereka.  Bila misalnya, suatu saat nanti,  kamu membuat client di Visual C++, maka IMahasiswaService ini akan terpakai.  Kamu tidak perlu khawatir takut kerepotan karena selama ini Visual C++ ATL telah membuatkan dua interface ini secara otomatis bagi kita.

Kembali ke diagram di atas, class Jocki.MahasiswaService akan memakai class lain yaitu Jocki.Mahasiswa.  Walaupun class ini menyediakan IDispatch, pengguna tidak seharusnya membuat class ini langsung dari PHP, karena tujuan utama class ini adalah dipakai oleh Jocki.MahasiswaService.  “Kenapa harus repot-repot membuat dua class?  Bukankah selama ini semua contoh selalu hanya satu class saja?”  demikian pikirmu.  Ini berkaitan dengan bagaimana mengembalikan isi tabel ke klien PHP.   Saat PHP memanggil getAllMahasiswa (ini hanya contoh!), kamu harus mengembalikan daftar list yang berisi … ?  array? Ok, tapi pengguna PHP harus ingat urutan index di array, misalnya index 0 adalah NIM, index 1 adalah nama, dan sebagainya.   Apa tidak ada cara lain yang lebih rapi sedikit?  Yup, itu sebabnya kita mengembalikan class Jocki.Mahasiswa.

Sekarang kamu akan merancang secara lebih detail lagi.  Coba lihat class diagram berikut ini:

Class Diagram MahasiswaService

Class Diagram MahasiswaService

CMahasiswaService adalah class yang mengimplementasikan IMahasiswaService.   Hierarki ini secara otomatis sudah dibuat oleh Visual C++ pada saat kamu wizard new ATL Simple Object.

Method Inisialisasi() akan dipakai untuk melakukan koneksi database.  Pengguna harus menyertakan user database, password, serta nama database yang dipakai saat memanggil method ini.   Bila method lain dipanggil sebelum method ini, maka method lain akan mengembalikan nilai kesalahan.  Pada perancangan yang lebih baik, kamu bisa menyediakan nilai default untuk user, password, dan nama db.  Lalu setiap kali method lain dipanggil dan ternyata koneksi belum dibuat, maka method Inisialiasi() akan dikerjakan dengan nilai default tersebut.

Selain melakukan koneksi database, method Inisialisasi juga akan menyiapkan PreparedStatement yang dibutuhkan.  PreparedStatement adalah class dari Connector/CPP untuk men-cache statement SQL sehingga pemanggilan query yang sama akan lebih cepat nantinya.  Selain itu, PreparedStatement akan mencegah terjadinya SQL Injection.  Pada diagram di atas, saya membuat beberapa PreparedStatement seperti psInsert, psUpdate, psDelete, psSelectByNIM, dan psSelectAll.

Setelah melakukan inisialisasi PreparedStatement, method Inisialisasi() juga akan melakukan query untuk mendapatkan seluruh isi tabel Mahasiswa melalui method Refresh() guna dipakai oleh _NewEnum() dan Item() nantinya.    Pada kasus yang lebih realistis dimana isi tabel mahasiswa sangat banyak sekali, kamu seharusnya hanya perlu men-select hanya bagian tertentu saja pada satu waktu tertentu, tidak semuanya sekaligus.

Setelah select seluruh data dilakukan pertama kali saat method Inisialisasi() dipanggil, mungkin saja user akan melakukan perubahan, seperti setelah pemanggilan HapusMahasiswa() atau SimpanMahasiswa().  Hal ini menyebabkan hasil query pertama kali menjadi tidak valid lagi.  Oleh sebab itu, user wajib memanggil method Refresh() untuk memperbaharui query.  Pada design yang lebih realistis, kamu perlu melakukan caching dan melakuan refresh secara otomatis sehingga user tidak perlu repot.

Method SimpanMahasiswa() akan dipakai untuk insert dan update.  Bila nim mahasiswa belum ada di tabel, maka program harus menambah (insert) record baru.  Tetapi bila nim sudah ada di tabel, maka program tinggal mengubah (update) record yang sudah ada.

Method HapusMahasiswa() dipakai untuk menghapus record berdasarkan nim.

“Lalu apa itu _NewEnum()?  Sungguh nama method yang aneh,” kamu bertanya dalam hati.  Ini adalah method spesial yang memungkinkan kamu memakai class kamu di PHP dengan syntax seperti berikut ini:

<?php
  $com = new COM("Jocki.MahasiswaService");
  foreach ($com as $i) {
     ...
  }
?>

“Pasti Item() juga pasti ada kaitannya?” tanyamu.  Iya, benar.  Item()memungkinkan kode program di PHP seperti berikut ini:

<?php
  $com = new COM("Jocki.MahasiswaService");
  $data1 = $com[1];
  $data2 = $com[2];
  $data3 = $com[3];
?>

Pada contoh di atas, kamu dapat melakukan perulangan setiap record yang ada dengan foreach di PHP berkat _NewEnum() dan kamu bisa mengakses record sebagai array berkat Item().   O ya, kamu tidak perlu membuat kode proram untuk kedua-duanya, karena kamu akan memakai class bawaan ATL yang bernama CComEnumOnSTL.

Berikutnya, seperti apa isi Jocki.Mahasiswa?  Coba perhatikan class diagram berikut ini:

Class Diagram Mahasiswa

Class Diagram Mahasiswa

Class CMahasiswa hanyalah class sederhana yang berisi property sehingga program PHP dapat mengakses setiap record di tabel mahasiswa seperti berikut ini:

<?php
  $com = new COM("Jocki.MahasiswaService");
  print "<h1>Daftar Mahasiswa</h1>";
  for($com as $mhs) {
    // tanpa class Mahasiswa, misalnya dengan array, akan menjadi: 
    // $mhs[0] untuk NIM, $mhs[1] untuk Nama, dsb.
    print "NIM: " . $mhs->NIM . "<br>";
    print "Nama: " . $mhs->Nama . "<br>";
    print "Tahun Masuk: " . $mhs->TahunMasuk . "<br>";
    print "<hr>";
  }
?>

Ok, setelah melihat dan memahami perancangan COM latihan kita, pada artikel berikutnya, kamu akan  membuat implementasinya.

COM DLL Akses MySQL – Bagian 5: Implementasi Kode Program

Tulisan ini merupakan bagian dari panduan membuat COM DLL (ATL) di Visual Studio 2010 yang mengakses MySQL atas request Albert Antonius:

Bila kamu masih bingung mempraktekkan langkah-langkah yang ada disini, baca dulu bagian 1 sampai 3. Buka Visual Studio 2010, buat sebuah proyek ATL baru dengan nama LatihanCRUDMahasiswa.  Lakukan pengaturan proyek seperti yang tunjukkan di artikel bagian 2. Tambahkan sebuah ATL Simple Object dengan nama Mahasiswa (short name).  Beri nilai ProgID dengan Jocki.Mahasiswa. Pada interface IMahasiswa, tambahkan property seperti berikut ini:

  • Property type bernilai BSTR dan Property name bernilai NIM.
  • Property type bernilai BSTR dan Property name bernilai Nama.
  • Property type bernilai int dan Property name bernilai TahunMasuk.

Tambahkan 3 variabel private di CMahasiswa, seperti berikut ini:

  • Variable type bernilai BSTR dan Variable name bernilai nim.
  • Variable type bernilai BSTR dan Variable name bernilai nama.
  • Variable type bernilai int dan Variable name bernilai tahunMasuk.

Buka file Mahasiswa.cpp dan lakukan modifikasi pada isi method hingga method yang ada memiliki isi seperti berikut ini:

STDMETHODIMP CMahasiswa::get_NIM(BSTR* pVal)
{
	CComBSTR bstr(nim);
	*pVal = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_NIM(BSTR newVal)
{
	CComBSTR bstr;
	bstr.Empty();
	bstr.AppendBSTR(newVal);
	nim = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::get_Nama(BSTR* pVal)
{
	CComBSTR bstr(nama);
	*pVal = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_Nama(BSTR newVal)
{
	CComBSTR bstr;
	bstr.Empty();
	bstr.AppendBSTR(newVal);
	nama = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::get_TahunMasuk(int* pVal)
{
	*pVal = tahunMasuk;
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_TahunMasuk(int newVal)
{
	tahunMasuk = newVal;
	return S_OK;
}

Class Mahasiswa cukup hanya sampai disini saja.  Bila kamu kode program yang lebih praktis, kamu bisa mendeklarasikan nim dan nama dengan tipe CComBSTR (anggap saja latihan buat kamu!) Sekarang, buat sebuah ATL Simple Object dengan nama MahasiswaService (short name) dan beri nilai ProgID dengan Jocki.MahasiswaService. Pada interface IMahasiswaService, tambahkan method:

  • Method name berupa Inisialisasi, mengandung parameter [in] BSTR user, [in] BSTR password, dan [in] BSTR namaDatabase.
  • Method name berupa SimpanMahasiswa, mengandung parameter [in] BSTR nim, [in] BSTR nama, dan [in] int tahunMasuk.
  • Method name berupa HapusMahasiswa, mengandung parameter [in] BSTR nim.
  • Method name berupa CariMahasiswaByNIM, mengandung parameter [in] BSTR nim dan [out, retval] IMahasiswa** ret.
  • Method name berupa Refresh.  Tidak mengandung parameter.

Coba buka isi file LatihanCRUDMahasiswa.idl, kamu harusnya menemukan bagian seperti berikut ini:

interface IMahasiswaService : IDispatch{
	[id(1)] HRESULT Inisialisasi([in] BSTR user, [in] BSTR password, [in] BSTR namaDatabase);
	[id(2)] HRESULT SimpanMahasiswa([in] BSTR nim, [in] BSTR nama, [in] int tahunMasuk);
	[id(3)] HRESULT HapusMahasiswa([in] BSTR nim);
	[id(4)] HRESULT Refresh(void);	
	[id(5)] HRESULT CariMahasiswaByNIM([in] BSTR nim, [out,retval] IMahasiswa** ret);
};

Sekarang, kamu akan menambahkan property baru secara manual dengan mengetik sehingga bagian di atas akan terlihat seperti berikut ini:

interface IMahasiswaService : IDispatch{
	[id(1)] HRESULT Inisialisasi([in] BSTR user, [in] BSTR password, [in] BSTR namaDatabase);
	[id(2)] HRESULT SimpanMahasiswa([in] BSTR nim, [in] BSTR nama, [in] int tahunMasuk);
	[id(3)] HRESULT HapusMahasiswa([in] BSTR nim);
	[id(4)] HRESULT Refresh(void);	
	[id(5)] HRESULT CariMahasiswaByNIM([in] BSTR nim, [out,retval] IMahasiswa** ret);
	[propget, id(DISPID_VALUE)] HRESULT Item([in] long n, [out, retval] IMahasiswa** ret);
	[propget, id(DISPID_NEWENUM)] HRESULT _NewEnum([out, retval] IUnknown** pVal);
};

Property Item dan _NewEnum dibutuhkan untuk membaca setiap record Mahasiswa yang ada.

Sekarang buka file MahasiswaService.h, tambahkan bagian berikut setelah #include "resource.h":

#include "Mahasiswa.h"
#include "mysql_connection.h"
#include <cppconn\driver.h>
#include <cppconn\exception.h>
#include <cppconn\prepared_statement.h>
#include <cppconn\statement.h>
using namespace sql;

Berikutnya, tambahkan private variable berikut ke dalam class CMahasiswaService:

  • Variable type: Driver* dan Variable name: driver.
  • Variable type: Connection* dan Variable name: cn.
  • Variable type: Statement* dan Variable name: stmt.
  • Variable type: PreparedStatement* dan Variable name: psInsert.
  • Variable type: PreparedStatement* dan Variable name: psUpdate.
  • Variable type: PreparedStatement* dan Variable name: psDelete.
  • Variable type: PreparedStatement* dan Variable name: psSelectByNIM.
  • Variable type: PreparedStatement* dan Variable name: psSelectAll.

Buka file MahasiswaService.cpp, lalu modifikasi implementasi method CMahasiswaService::Inisialisasi()sehingga terlihat seperti berikut ini:

STDMETHODIMP CMahasiswaService::Inisialisasi(BSTR user, BSTR password, BSTR namaDatabase)
{
	// Bila inisialisasi sudah pernah dipanggil, hapus terlebih dahulu instance
	// yang sudah pernah dibuat.
	if (cn!=NULL) {		
		delete stmt;
		delete psDelete;
		delete psInsert;
		delete psSelectAll;
		delete psSelectByNIM;
		delete psUpdate;
		delete cn;
	}

	// Membuat koneksi ke database
	char strUser[100], strPassword[100], strNamaDatabase[100];
	size_t len;
	wcstombs_s(&len, strUser, user, 100);
	wcstombs_s(&len, strPassword, password, 100);
	wcstombs_s(&len, strNamaDatabase, namaDatabase, 100);

	try {

		driver = get_driver_instance();
		cn = driver->connect("tcp://127.0.0.1:3306", strUser, strPassword);
		cn->setSchema(strNamaDatabase);

		// Membuat tabel Mahasiswa bila belum dibuat
		stmt = cn->createStatement();
		stmt->execute("CREATE TABLE IF NOT EXISTS tblMahasiswa (nim CHAR(10), nama VARCHAR(200), tahunMasuk INT)");

		// Menyiapkan PreparedStatement
		psSelectAll = cn->prepareStatement("SELECT nim, nama, tahunMasuk FROM tblMahasiswa");
		psSelectByNIM = cn->prepareStatement("SELECT nim, nama, tahunMasuk FROM tblMahasiswa WHERE nim = ?");
		psUpdate = cn->prepareStatement("UPDATE tblMahasiswa SET nama = ?, tahunMasuk = ? WHERE nim = ?");
		psDelete = cn->prepareStatement("DELETE FROM tblMahasiswa WHERE nim = ?");
		psInsert = cn->prepareStatement("INSERT INTO tblMahasiswa(nim, nama, tahunMasuk) VALUES (?, ?, ?)");

		// Melakukan query seluruh data di tblMahasiswa
                this->Refresh();

	} catch (SQLException &e) {
		return E_FAIL;
	}

	return S_OK;
}

Method Inisialisasi() bertanggung jawab untuk menyiapkan koneksi database sehingga dapat dipakai oleh pemanggil method-method lainnya.

Berikutnya, lakukan modifikasi pada CMahasiswaService::SimpanMahasiswa()sehingga terlihat seperti berikut ini:

STDMETHODIMP CMahasiswaService::SimpanMahasiswa(BSTR nim, BSTR nama, int tahunMasuk)
{
	// Konversi BSTR menjadi SQLString
	char strNIM[11], strNama[201];	
	size_t len;
	wcstombs_s(&len, strNIM, nim, 10);
	wcstombs_s(&len, strNama, nama, 200);

	// Memeriksa apakah record sudah pernah tersimpan atau tidak	
	try {
		psSelectByNIM->setString(1, strNIM);
		if (psSelectByNIM->executeQuery()->next()) {

			// Record sudah tersimpan, lakukan proses update
			psUpdate->setString(1, strNama);
			psUpdate->setInt(2, tahunMasuk);
			psUpdate->setString(3, strNIM);
			psUpdate->executeUpdate();

		} else {

			// Record belum tersimpan, lakukan proses insert
			psInsert->setString(1, strNIM);
			psInsert->setString(2, strNama);
			psInsert->setInt(3, tahunMasuk);
			psInsert->executeUpdate();

		}
	} catch (SQLException &e) {
		return E_FAIL;
	}

	return S_OK;
}

Method CMahasiswa::SimpanMahasiswa() adalah sebuah method yang melakukan salah satu dari operasi insert atau update. Bila NIM yang diberikan sudah tersimpan di tabel, maka method ini akan memberikan query SQL UPDATE. Namun bila NIM yang diberikan belum pernah tersimpan, maka method ini akan memberikan query SQL INSERT. Cara seperti ini akan mempermudah user yang memakai DLL ini karena mereka hanya perlu “mempelajari” satu method. Kelemahannya adalah kinerja yang berkurang karena harus selalu melakukan SELECT untuk memeriksa apakah record sudah pernah tersimpan atau belum.

Berikutnya, lakukan modifikasi pada CMahasiswa::HapusMahasiswa()sehingga kode programnya terlihat seperti berikut ini:

STDMETHODIMP CMahasiswaService::HapusMahasiswa(BSTR nim)
{
	// Konversi BSTR menjadi SQLString
	char strNIM[11];
	size_t len;
	wcstombs_s(&len, strNIM, nim, 10);	

	// Menghapus record berdasarkan NIM
	try {

		psDelete->setString(1, strNIM);
		psDelete->executeUpdate();

	} catch (SQLException &e) {
		return E_FAIL;
	}

	return S_OK;
}

Method CMahasiswaService::HapusMahasiswa() adalah method yang sederhana, hanya menghapus data di tabel berdasarkan parameter NIM yang diberikan.

Berikutnya, cari method CMahasiswaService::CariMahasiswaByNIM()dan lakukan perubahan sehingga isinya akan terlihat seperti berikut ini:

STDMETHODIMP CMahasiswaService::CariMahasiswaByNIM(BSTR nim, IMahasiswa** ret)
{
	// Konversi BSTR menjadi SQLString
	char strNIM[11];
	size_t len;
	wcstombs_s(&len, strNIM, nim, 10);	

	try {

		ResultSet* rs;

		// Melakukan query untuk mencari record berdasarkan NIM
		psSelectByNIM->setString(1, strNIM);
		rs = psSelectByNIM->executeQuery();
		if (rs->next()) {

			// Record ditemukan.  Buat instance class Mahasiswa dan
			// inisialisasi nilai, serta kembalikan nilainya.
			CComPtr ptrMahasiswa;
			ptrMahasiswa.CoCreateInstance(CLSID_Mahasiswa);
			IMahasiswa* pMahasiswa = (IMahasiswa*) ptrMahasiswa;
			CComBSTR bstrNIM(rs->getString(1)->c_str());
			pMahasiswa->put_NIM(bstrNIM);
			CComBSTR bstrNama(rs->getString(2)->c_str());
			pMahasiswa->put_Nama(bstrNama);
			pMahasiswa->put_TahunMasuk(rs->getInt(3));						
			ptrMahasiswa.CopyTo(ret);
		}

		delete rs;

	} catch (SQLException &e) {
		return E_FAIL;
	}

	return S_OK;
}

Method CMahasiswaService::CariMahasiswaByNIM() mengembalikan pointer ke IMahasiswa. Ini berarti, di PHP nanti, kita bisa membuat kode program seperti:

<?php   
  $com = new COM("Jocki.MahasiswaService");   
  $com->Inisialisasi("root", "password", "dbLatihan");

  // Cara 1
  $mhs = $com->CariMahasiswaByNIM("1103030023");
  print "Nama [" . $mhs->Nama . "]<br>";

  // Atau, Cara 2
  print "Nama [" . $com->CariMahasiswaByNIM("1103030023")->Nama . "]<br>";
?>

Programmer PHP (selaku “konsumen“) bisa memakai hasil kembalian dari operasi pencarian berdasarkan NIM secara lebih leluasa (walaupun lebih repot bagi kamu selaku “produsen” ;). Tanpa class Mahasiswa, maka hasil kembalian dapat berupa array yang lebih tidak nyaman dipakai.

Sekarang, dari semua operasi CRUD, kamu telah mengimplementasikan Create, Update dan Delete. Langkah terakhir adalah membuat implementasi Read.  Operasi yang satu ini berbeda dengan yang lainnya, karena saat kita mengembalikan isi tabel, kita tidak hanya mengembalikan satu nilai, melainkan kumpulan nilai.  Istilah COM-nya adalah Collection.  Kamu membutuhkan sebuah class khusus untuk menampung kumpulan nilai tersebut.  Selain itu, kamu membutuhkan sebuah cara untuk mengakses Collection, yang disebut sebagai Enumerator.  Beruntungnya, ATL menyediakan class yang dapat langsung kamu pakai.  Masih ingat dengan property Item dan _NewEnum yang kamu buat sebelumnya?  Ini akan dipakai untuk Enumerator.  Kamu tidak akan membuat implementasinya secara manual karena kamu akan memakai CComEnumOnSTL dan IEnumVARIANT yang disediakan oleh ATL.

Buka file MahasiswaService.h, lalu tambahkan kode program berikut setelah baris using namespace ATL:

#include <list>
struct _CopyVariantFromAdaptItf {
 static HRESULT copy(VARIANT* p1, const CAdapt<CComPtr<IMahasiswa>>* p2) {
 HRESULT hr = p2->m_T->QueryInterface(IID_IDispatch, (void**) &p1->pdispVal);
 p1->vt = VT_DISPATCH;
 return hr;
 }
static void init(VARIANT* p) { VariantInit(p); }
 static void destroy(VARIANT* p) {VariantClear(p); }
};
typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _CopyVariantFromAdaptItf, std::list<CAdapt<CComPtr<IMahasiswa>>>> 
 CComEnumVariantOnMahasiswaService;
struct _CopyItfFromAdaptItf {
 static HRESULT copy(IMahasiswa** p1, const CAdapt<CComPtr<IMahasiswa>>* p2) {
 if (*p1=p2->m_T) return (*p1)->AddRef(), S_OK;
 return E_POINTER;
 }
 static void init(IMahasiswa** p) {}
 static void destroy(IMahasiswa** p) {if (*p) (*p)->Release();}
};
typedef ICollectionOnSTLImpl<
 IDispatchImpl<IMahasiswaService, &IID_IMahasiswaService>,
 std::list<CAdapt<CComPtr<IMahasiswa>>>,
 IMahasiswa*,
 _CopyItfFromAdaptItf,
 CComEnumVariantOnMahasiswaService>
 IMahasiswaServiceCollImpl;

Kemudian, cari bagian definisi class CMahasiswaService di bawahnya, dan ubah sehingga terlihat seperti berikut ini:

class ATL_NO_VTABLE CMahasiswaService :
 public CComObjectRootEx<CComSingleThreadModel>,
 public CComCoClass<CMahasiswaService, &CLSID_MahasiswaService>,
 public IMahasiswaServiceCollImpl

Berikutnya, cari method CMahasiswaService::Refresh() dan lakukan perubahan sehingga isinya akan terlihat seperti berikut ini:

STDMETHODIMP CMahasiswaService::Refresh(void)
{
try {
	ResultSet* rs;

	// Melakukan select seluruh baris di tabel
	rs = psSelectAll->executeQuery();

	while (rs->next()) {
		// Membuat pointer ke  CMahasiswa
		CComPtr ptrMahasiswa;
		ptrMahasiswa.CoCreateInstance(CLSID_Mahasiswa);
		IMahasiswa* pMahasiswa = (IMahasiswa*) ptrMahasiswa;
		CComBSTR bstrNIM(rs->getString(1)->c_str());
		CComBSTR bstrNama(rs->getString(2)->c_str());
		pMahasiswa->put_NIM(bstrNIM);
		pMahasiswa->put_Nama(bstrNama);
		pMahasiswa->put_TahunMasuk(rs->getInt(3));
		m_coll.push_back(ptrMahasiswa);
	}

	delete rs;

} catch (SQLException &e) {
	return E_FAIL;
}

return S_OK;
}

Ok, sekarang kamu telah selesai!  Pilih menu Build, Build Solution untuk membuat output DLL dari proyek kamu.

Kamu bisa membuat sebuah halaman PHP untuk menguji operasi CRUD database, misalnya dengan halaman PHP berikut ini:

<!DOCTYPE html>
<html>
<head>
 <title>Latihan COM DLL - Operasi CRUD MySQL</title>
 <style type="text/css">
 table { border-collapse: collapse; border: 1px solid black;}
 td { padding: 10px; }
 th { border-bottom: 3px double black; padding: 5px;}
 </style>
</head>
<?php
 $aksi = $_REQUEST['aksi']; 
 if ($aksi=='') $aksi='lihat';
 $myself = $_SERVER['PHP_SELF'];

 $mahasiswaService = new COM("Jocki.MahasiswaService");
 $mahasiswaService->Inisialisasi("root", "password", "namadb");
if ($aksi=='tambah') {
?> 
 <h1>Tambah Mahasiswa</h1>
 <form action="<?php print $myself;?>" method="POST">
 <fieldset>
 <p>
 <label for="txtNIM">NIM:</label>
 <input type="text" name="txtNIM" size="10" />
 </p>
 <p>
 <label for="txtNama">Nama:</label>
 <input type="text" name="txtNama" size="50"/>
 </p> 
 <p>
 <label for="txtTahunMasuk">Tahun Masuk:</label>
 <input type="text" name="txtTahunMasuk" size="5"/>
 </p>
 <input type="hidden" name="aksi" value="prosesTambah"/>
 <input type="submit" value="Tambah Mahasiswa"/> 
 </fieldset>
 </form>

<?php 
 } else if ($aksi=='prosesTambah') {
$nim = $_POST['txtNIM'];
 $nama = $_POST['txtNama'];
 $tahunMasuk = $_POST['txtTahunMasuk'];
 $mahasiswaService->SimpanMahasiswa($nim, $nama, $tahunMasuk);
 header("Location: $myself");

 } else if ($aksi=='hapus') {

 $nim = $_GET['txtNIM'];
 $mahasiswaService->HapusMahasiswa($nim); 
 header("Location: $myself");

 } else if ($aksi=='update') {

 $nim = $_GET['txtNIM'];
 $mahasiswa = $mahasiswaService->CariMahasiswaByNIM($nim);
?> 

 <h1>Update Mahasiswa</h1>
 <form action="<?php print $myself;?>" method="POST">
 <fieldset>
 <p>
 NIM: <?php print $nim; ?> 
 <input type="hidden" name="txtNIM" value="<?php print $nim; ?>" />
 </p>
 <p>
 <label for="txtNama">Nama:</label>
 <input type="text" name="txtNama" size="50" value="<?php print $mahasiswa->Nama; ?>"/>
 </p> 
 <p>
 <label for="txtTahunMasuk">Tahun Masuk:</label>
 <input type="text" name="txtTahunMasuk" size="5" value="<?php print $mahasiswa->TahunMasuk; ?>"/>
 </p>
 <input type="hidden" name="aksi" value="prosesTambah"/>
 <input type="submit" value="Update Mahasiswa"/> 
 </fieldset>
 </form>

<?php 
 } else if ($aksi=='lihat') {
?> 
 <h1>List Mahasiswa</h1>
 <table>
 <thead>
 <tr><th>NIM</th><th>Nama</th><th>Tahun Masuk</th><th>Operasi</th></tr>
 </thead>
 <tbody>
 <?php 
 foreach ($mahasiswaService as $mahasiswa) {
 $nim = $mahasiswa->NIM;
 print "<tr>" .
 "<td>" . $nim . "</td>" .
 "<td>" . $mahasiswa->Nama . "</td>" .
 "<td>" . $mahasiswa->TahunMasuk . "</td>" .
 "<td><a href='$myself?aksi=hapus&txtNIM=$nim'>Hapus</a> - " .
 "<a href='$myself?aksi=update&txtNIM=$nim'>Edit</a></td>" .
 "</tr>";
 }
 ?>
 </tbody>
 </table>
 <a href="<?php print $myself; ?>?aksi=tambah">Tambah Data Mahasiswa Baru</a>
<?php 
 } 
?>
</html>

File PHP di atas belum mencakup validasi, tetapi cukup untuk menguji apakah operasi CRUD database melalui COM DLL berfungsi dengan baik.

COM DLL Akses MySQL – Bagian 3: Operasi Database Insert

Tulisan ini merupakan bagian dari panduan membuat COM DLL (ATL) di Visual Studio 2010 yang mengakses MySQL atas request Albert Antonius:

Mari mulai dengan membuat sebuah ATL Object.  Caranya adalah dengan membuka Class View.  Bila tab Class View tidak muncul, pilih menu View, Class View.  Klik kanan pada LatihanCOM, dan pilih Add, Class… Pada dialog yang muncul, pilih ATL Simple Object kemudian klik tombol Add. Isi dialog ATL Simple Object Wizard dengan memberi nama Mahasiswa pada Short name serta Latihan.Mahasiswa pada ProgID seperti yang terlihat di gambar berikut ini:

Membuat ATL Object Baru

Membuat ATL Object Baru

Klik tombol Finish. Bila kamu masih bingung dengan langkah ini, coba baca kembali artikel pengenalan di sini.

Sekarang kita akan menambahkan property DBUser untuk menampung user name yang dipakai untuk akses database nantinya. Masih di Class View, klik kanan pada interface IMahasiswa, pilih Add, Add Property… Isi Property Type dengan BSTR dan isi Property name dengan DBUser seperti yang terlihat pada gambar berikut:

Membuat Property DBUser

Membuat Property DBUser

Klik tombol Finish.

Lakukan hal yang sama untuk menambahkan property DBPassword yang menampung password untuk akses database MySQL, seperti yang terlihat pada gambar berikut:

Membuat Property DBPassword

Membuat Property DBPassword

Klik tombol Finish.

Kembali lakukan hal yang sama untuk menambahkan property DBNama yang menampung nama database MySQL yang akan dipakai, seperti yang terlihat pada gambar berikut:

Membuat Property DBNama

Membuat Property DBNama

Klik tombol Finish.

Apa itu BSTR? Tebakanmu benar, BSTR adalah tipe data String versi COM. Ingat bahwa COM adalah teknologi yang tidak terikat oleh bahasa. Padahal, hampir setiap bahasa memiliki tipe data String tersendiri, misalnya di bahasa C memakai char*, bahasa C++ memakai class string, bahasa Java memakai class java.lang.String, dan sebagainya.

Sekarang kita akan membuat deklarasi method, yaitu method Inisialisasi. Method ini akan melakukan pemeriksaan database dan membuat tabel yang dibutuhkan. Caranya adalah dengan klik kanan pada interface IMahasiswa, pilih Add, Add Methods… Pada dialog yang muncul, isi Method name dengan Inisialisasi, seperti yang terlihat pada gambar berikut ini:

Membuat Method Inisialisasi

Membuat Method Inisialisasi

Klik tombol Finish.

Lalu buat method lain, yaitu method TambahMahasiswa. Caranya adalah dengan klik kanan pada interface IMahasiswa, lalu pilih Add, Add Method… Pada dialog yang muncul, isi Method name dengan TambahMahasiswa. Berikan tiga parameter [in] berupa BSTR nim, BSTR nama, dan int tahunMasuk seperti yang terlihat pada gambar berikut ini:

Membuat Method TambahMahasiswa

Membuat Method TambahMahasiswa

Klik tombol Finish.

Bila kamu melakukan langkah-langkah yang ada dengan benar, di file LatihanCOM.idl, kamu akan menemukan bagian berikut ini:

interface IMahasiswa : IDispatch{
	[propget, id(1)] HRESULT DBUser([out, retval] BSTR* pVal);
	[propput, id(1)] HRESULT DBUser([in] BSTR newVal);
	[propget, id(2)] HRESULT DBPassword([out, retval] BSTR* pVal);
	[propput, id(2)] HRESULT DBPassword([in] BSTR newVal);
	[propget, id(3)] HRESULT DBNama([out, retval] BSTR* pVal);
	[propput, id(3)] HRESULT DBNama([in] BSTR newVal);
	[id(4)] HRESULT TambahMahasiswa([in] BSTR nim, [in] BSTR nama, [in] int tahunMasuk);
	[id(5)] HRESULT Inisialisasi(void);
};

Seperti yang kamu ketahui, interface hanya sebuah kontrak tanpa isi. Interface adalah sebuah janji tanpi aksi. Oleh sebab itu, kamu perlu membuat implementasi dari interface IMahasiswa.

Tapi sebelumnya, masih ingat kamu membuat tiga property, yaitu DBUser, DBPassword, dan DBNama? Kamu perlu membuat tiga variabel untuk menampung masing-masing nilai tersebut. Kamu bisa mengubah definisi class secara langsung di file Mahasiswa.h, tetapi biar gampang, kamu dapat menambahkan variabel melalui wizard. Pastikan kamu masih berada di Class View. Klik kanan pada class CMahasiswa, pilih Add, Add Variable… Pada Access, plih private. Pada Variable type, ketik char[100]. Pada Variable name, isi dengan m_dbUser, sehingga dialog akan terlihat seperti:

Membuat private member variable

Membuat private member variable

Klik tombol Finish.

Lakukan hal yang sama untuk membuat variabel m_dbPassword dan m_dbNama. Kedua variabel tersebut juga sama-sama bertipe char[100]. Yup, kita membatasi hingga maksimal 100 karakter.

Setelah interface dan variabel selesai dibuat, pertanyaannya adalah dimana kamu meletakkan implementasi kode program?  Buka Solution Explorer (bila kamu tersesat, klik menu View, Solution Explorer). Kemudian double click pada file Mahasiswa.cpp. Disini adalah tempat kamu meletakkan isi dari method untuk class CMahasiswa.

Kita akan mulai dengan get/put untuk property yang ada. Ganti method yang bersangkutan sehingga isinya terlihat seperti berikut ini:

size_t len;

STDMETHODIMP CMahasiswa::get_DBUser(BSTR* pVal)
{
	CComBSTR bstr(m_dbUser);	
	*pVal = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_DBUser(BSTR newVal)
{	
	wcstombs_s(&len, m_dbUser, newVal, 99);	
	return S_OK;
}

STDMETHODIMP CMahasiswa::get_DBPassword(BSTR* pVal)
{
	CComBSTR bstr(m_dbPassword);
	*pVal = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_DBPassword(BSTR newVal)
{	
	wcstombs_s(&len, m_dbPassword, newVal, 99);
	return S_OK;
}

STDMETHODIMP CMahasiswa::get_DBNama(BSTR* pVal)
{
	CComBSTR bstr(m_dbNama);
	*pVal = bstr.Detach();
	return S_OK;
}

STDMETHODIMP CMahasiswa::put_DBNama(BSTR newVal)
{	
	wcstombs_s(&len, m_dbNama, newVal, 99);
	return S_OK;
}

Saya menambahkan sebuah deklarasi size_t len karena variabel yang sama ini akan dipakai pada saat pemanggilan fungsi wcstombs_s(). Btw, di sini saya menggunakan class CComBSTR milik framework ATL untuk melakukan konversi char* (C string) menjadi BSTR. Sebaliknya, untuk melakukan konversi BSTR menjadi char* (C string), saya menggunakan fungsi wcstombs_s().
Berikutnya, saya akan menambahkan deklarasi method Inisialisasi. Tapi karena akan memakai Connector/CPP, maka saya menambahkan baris berikut ini di bagian atas di class Mahasiswa.cpp:

#include "mysql_connection.h"
#include <cppconn\driver.h>
#include <cppconn\exception.h>
#include <cppconn\prepared_statement.h>
#include <cppconn\statement.h>

using namespace sql;

Lalu, saya mengubah method Inisialisasi sehingga terlihat seperti berikut ini:

STDMETHODIMP CMahasiswa::Inisialisasi(void)
{
	Driver* driver;
	Connection* con;
	Statement* st;

	driver = get_driver_instance();
	con = driver->connect("tcp://127.0.0.1:3306", m_dbUser, m_dbPassword);
	con->setSchema(m_dbNama);

	st = con->createStatement();
	st->execute("CREATE TABLE IF NOT EXISTS tblMahasiswa (nim CHAR(10), nama VARCHAR(200), tahunMasuk INT)");
	delete st;
	delete con;

	return S_OK;
}

Method ini akan secara otomatis membuat sebuah tabel dengan nama tblMahasiswa bila tabel tersebut belum ada. Biar cepat, saya mengandaikan bahwa server MySQL berada di komputer yang sama (IP 127.0.0.1). Saya juga mengabaikan penanganan kesalahan disini.

Sekarang, ubah method TambahMahasiswa sehingga terlihat seperti berikut ini:

STDMETHODIMP CMahasiswa::TambahMahasiswa(BSTR nim, BSTR nama, int tahunMasuk)
{
	Driver* driver;
	Connection* con;
	PreparedStatement* ps;
	char pNim[11];
	char pNama[201];
	wcstombs_s(&len, pNim, nim, 10);
	wcstombs_s(&len, pNama, nama, 200);

	driver = get_driver_instance();
	con = driver->connect("tcp://127.0.0.1:3306", m_dbUser, m_dbPassword);
	con->setSchema(m_dbNama);

	ps = con->prepareStatement("INSERT INTO tblMahasiswa(nim, nama, tahunMasuk) VALUES (?,?,?)");
	ps->setString(1, pNim);
	ps->setString(2, pNama);
	ps->setInt(3, tahunMasuk);
	ps->executeUpdate();

	delete ps;
	delete con;

	return S_OK;
}

Langkah terakhir untuk COM kita adalah membuatnya dengan memilih menu Build, Build Solution. Jika tidak ada pesan kesalahan, maka kita siap untuk lanjut ke tahap berikutnya.

Yang perlu kamu lakukan berikutnya adalah membuat sebuah database baru di MySQL Server. Kamu juga boleh memakai database yang sudah ada. Kamu dapat membuat database baru dengan menggunakan PHPMyAdmin, dan jika kamu terbiasa memakai MySQL Console, maka kamu dapat memberikan perintah:

CREATE DATABASE nama_database;
GRANT ALL ON nama_database.* to nama_user@`127.0.0.1`;

Wow.. Perjalanan yang panjang,  bukan? Tapi percayalah, dibalik sesuatu yang rumit selalu ada kesederhanaan. Kamu sudah membuat bagian rumit-nya, sekarang saatnya menikmati hasil jerih payah kamu.

Buat sebuah halaman PHP dengan seperti berikut ini:

<?php
 if (isset($_GET['txtNIM']) && isset($_GET['txtNama']) && 
 isset($_GET['txtTahunMasuk'])) {

 $com = new COM("Latihan.Mahasiswa");
 $com->DBUser = "root";
 $com->DBPassword = "password";
 $com->DBNama = "latihan";
 $com->Inisialisasi();

 $nim = $_GET['txtNIM'];
 $nama = $_GET['txtNama'];
 $tahunMasuk = $_GET['txtTahunMasuk'];
 $com->TambahMahasiswa($nim, $nama, $tahunMasuk);
}
?>
<html>
<head><title>Latihan Insert</title></head>
<body>
<form action="<?php print $_SERVER['PHP_SELF'] ?>" method="GET">
 <p>NIM: <input type="text" name="txtNIM" size="10" /></p>
 <p>Nama: <input type="text" name="txtNama" size="20" /></p>
 <p>Tahun Masuk: <input type="text" name="txtTahunMasuk" size="10" /></p>
 <p><input type="submit" value="Simpan" /></p>
</form>
</body>
</html>

Pada kode program di atas, jangan lupa menyesuaikan user, password, dan nama database.

Sekarang,  buka halaman PHP tersebut di browser, isi data pada form yang muncul dan klik tombol Simpan. Kemudian periksa isi tabel tblMahasiswa dengan menggunakan PHPMyAdmin ataupun MySQL Console. Jika kamu mengikuti langkah yang ada dengan benar, maka data yang kamu masukkan akan tersimpan ke tabel tblMahasiswa.

Kode program PHP yang mengakses database terlihat sederhana & singkat, bukan? Tapi membuat COM DLL-nya terasa penuh perjuangan, bukan? Lain kali bila kamu melihat sesuatu yang sederhana, kamu mungkin telah sadar bahwa dibaliknya pasti ada yang bekerja keras menyembunyikan kerumitannya.  Sebenarnya, banyak kerumitan bisa dihindari, misalnya bila kamu memakai ADO atau memakai DLL .NET, yang nantinya tidak beda bila memakai Java dengan Web Service (SOAP).  Tapi tidak setidaknya, kamu sudah merasakan sesuatu yang low-level (semakin low-level semakin rumit, sehingga muncullah teknologi high-level untuk menyembunyikan kerumitan dan membuat orang-orang lupa bahwa low-level sebenarnya eksis).

Memanggil DLL dari PHP

Pada suatu hari, seorang mahasiswa yang sedang menyusun skripsi menanyakan pada saya apakah mungkin mengakses DLL dari kode program PHP.  Sebuah pertanyaan yang tidak terduga, karena saya sama sekali tidak pernah dan tidak berpikiran untuk melakukan hal tersebut.  Hal ini karena PHP adalah bahasa pemograman yang berada di banyak platform, gratis, dan sangat populer di Linux.  Sementara teknologi DLL adalah teknologi yang sangat terikat pada Microsoft Windows serta Visual Studio-nya.  Menurut saya, pertanyaan ‘membaca DLL‘ akan lebih selaras bila dipadukan dengan teknologi ASP.NET dengan bahasa C# ataupun VB, dibandingkan dengan PHP.

Kembali ke pertanyaan semula, apakah mungkin memanggil DLL dari PHP? Setelah melakukan pencarian di PHP Manual, saya menemukan bagian COM and .Net (Windows) yang dapat diakses di www.php.net/manual/en/book.com.php.  PHP memang mendukung Component Object Model (COM) dan .NET.  Lalu apa hubungan COM dan DLL?

  • DLL (Dynamic-link Library) adalah implementasi shared-library di platform Windows.  Programmer membuat fungsi yang dapat dipanggil ulang di program berbeda.
  • COM (Component Object Model) adalah sebuah metodologi yang mengatur bagaimana menerapkan komponen program yang dapat dipakai ulang di program berbeda.
  • COM tidak mengatur struktur bahasa yang dipakai (menurut referensi MSDN, COM sering salah kaprah diangagp sebagai OOP).
  • Implementasi COM umumnya dalam bentuk file DLL.
  • Tidak semua DLL dibuat berdasarkan aturan COM, atau dengan kata lain tidak semua DLL adalah COM.

Jadi  jawaban untuk mahasiswa tersebut adalah: bila DLL dibuat dengan menggunakan teknologi COM, maka DLL tersebut dapat diakses di PHP.  Bila DLL tersebut adalah DLL sederhana, maka DLL tersebut tidak dapat diakses di PHP.

Lalu bagaimana bila ingin tetap mengakses DLL sederhana di PHP?  Ada sebuah extension PHP yang dikhususkan untuk Windows yang bernama WinBinder.  Dengan WinBinder, programmer PHP dapat memanggil semua APIs Windows dengan PHP, membuat program GUI berbasis PHP, bahkan memanggil DLL sederhana (tanpa COM) dengan PHP.

Pada artikel ini, saya akan menggunakan teknologi sebagai berikut:

  • Visual C++ di Visual Studio 2010 untuk menghasilkan DLL yang mengikuti spesifikasi COM.
  • Memakai ATL (Active Template Library) di Visual C++ untuk membuat COMATL bukan bagian dari COM ataupun bahasa C++ melainkan sebuah framework sebagai bagian dari Visual C++ untuk mempermudah pembuatan COM.
  • PHP untuk mengakses DLL yang dihasilkan oleh Visual C++

Untuk membuat COM di Visual C++ dengan bantuan ATL, pilih menu File, New, Project di Visual Studio 2010.  Kemudian pada Visual C++, pilih ATL Project.  Beri nama pada project tersebut, misalnya LatihanCOM.  Tentukan juga lokasi folder untuk penyimpanan project tersebut.  Kemudian klik tombol OK.

Membuat Project ATL Baru

Membuat Project ATL Baru

Akan muncul ATL Project Wizard yang terdiri atas dua langkah.  Klik tombol Next pada wizard tersebut.  Pastikan pada Application Type, pilihan Dynamic-link library (DLL) terpilih.  Kemudian klik tombol Finish untuk membuat project.

ATL Project Wizard

ATL Project Wizard

Setelah project selesai dibuat, buka panel Class View.  Bila panel ini tertutup, pilih menu View, Class View (Ctrl+Shift+C) untuk menampilkannya.  Klik kanan pada nama project, LatihanCOM, kemudian pilih Add, Class…  Pada window Add Class yang muncul, pilih ATL Simple Object.  Kemudian klik tombol Add untuk melanjutkan.

Tampilan Dialog Add Class

Tampilan Dialog Add Class

Pada tampilan ATL Simple Object Wizard yang muncul, ketik nama Perhitungan di Short name.  Nama lain akan di-isi secara otomatis.  Pastikan bahwa di bagian COM, nama Interface adalah IPerhitungan.  Kemudian isi ProgID dengan nama Jocki.Perhitungan.  Window tersebut harus terlihat seperti berikut ini:

ATL Simple Object Wizard

ATL Simple Object Wizard

Klik tombol Finish untuk menyelesaikan wizard.

Buka panel Class View dan cari COM Interface yang bernama IPerhitungan.  Interface ini dibuat secara otomatis oleh Visual C++ sehingga yang perlu kita lakukan hanya menambahkan method yang akan dipanggil oleh program lain.  Klik kanan pada IPerhitungan, kemudian pilih Add, Add Method…

Menambah Method Pada COM Interface

Menambah Method Pada COM Interface

Pada dialog Add Method Wizard yang muncul, kita akan membuat sebuah method sederhana.  Method ini akan menerima parameter berupa dua buah bilangan bulat, kemudian mengembalikan hasil jumlah dua bilangan tersebut.  Pada method name, beri nama HitungJumlah.  Kemudian tambahkan dua parameter input dengan mengikuti langkah ini:

  1. Beri centang pada checkbox in di Parameter attributes.
  2. Ketik int di Parameter type.
  3. Ketik nilai1 di Parameter name.
  4. Klik tombol Add.
  5. Beri centang pada checkbox in di Parameter attributes.
  6. Ketik int di Parameter type.
  7. Ketik nilai2 di Parameter name.
  8. Klik tombol Add.

Setelah menambahkan parameter, tambahkan nilai kembalian dengan mengikuti langkah ini:

  1. Ketik int* di Parameter type.  Jangan lupa menambahkan * setelah int karena variabel ini akan merujuk ke hasil kembalian (pointer).  Bila tidak ada * setelah int, wizard tidak akan memberikan pilihan untuk mencentang checkbox out dan retval di langkah berikutnya.
  2. Beri tanda centang checkbox out dan checkbox retval.
  3. Ketik hasil pada Parameter name.
  4. Klik tombol Add.

Tampilan wizard akan terlihat seperti berikut ini:

Tampilan Add Method Wizard

Tampilan Add Method Wizard

Klik tombol Finish untuk menyelesaikan wizard.

Cari baris kode program seperti berikut ini di file Perhitungan.cpp:

STDMETHODIMP CPerhitungan::HitungJumlah(int nilai1, int nilai2, int* hasil)
{
// TODO: Add your implementation code here

return S_OK;
}

Kode program ini merupakan implementasi dari method yang akan dipanggil oleh PHP nantinya.  Ganti baris yang diawali dengan //TODO sehingga kode programnya akan terlihat seperti berikut ini:

STDMETHODIMP CPerhitungan::HitungJumlah(int nilai1, int nilai2, int* hasil)
{ *hasil = nilai1 + nilai2;

return S_OK;
}

Langkah terakhir sebelum menghasilkan DLL adalah melakukan sedikit perubahan pada settingan project.  Buka panel Solution Explorer.  Bila panel ini tertutup, pilih menu View, Solution Explorer (Ctrl+Alt+L).  Klik kanan pada nama project, LatihanCOM, kemudian pilih Properties.  Pada baris Per-user Redirection, ganti nilai No menjadi Yes.  Hal ini dilakukan untuk menghindari hal-hal yang berkaitan dengan masalah hak akses user.  Dengan mengaktifkan Per-user Redirection, DLL yang dihasilkan hanya akan tersedia oleh user Windows yang sedang aktif saat ini saja.

Untuk membuat DLL, pilih menu Build, Build Solution (Ctrl+Shift+B).  File DLL yang dihasilkan terletak di folder Debug di lokasi penyimpanan project.  Sebagai contoh, jika saya menyimpan project di Desktop, maka file DLL yang dihasilkan adalah C:\Users\JockiHendry\Desktop\LatihanCOM\Debug\LatihanCOM.dll.  Visual C++ 2010 telah melakukan registrasi DLL secara otomatis sehingga kita tidak perlu repot-repot lagi.

Sekarang, kita akan melakukan pengujian apakah DLL tersebut dapat dipanggil dengan baik.  Buat sebuah file PHP dengan isi seperti berikut ini:

<?php
   $perhitungan = new COM("Jocki.Perhitungan");
   $hasil = $perhitungan->HitungJumlah(11,22);
   print "Hasil dari method di COM DLL adalah $hasil";
?>

Bila kode program PHP di atas dijalankan, hasilnya adalah:

Hasil dari method di COM DLL adalah 33

Apa langkah berikutnya?

  • Ingin memanggil COM yang berada di komputer lain?  Pelajari Distributed COM (DCOM) lebih lanjut.
  • Tidak ingin memakai teknologi COM melainkan ingin memakai simple DLL?  Lihat solusi yang ditawarkan oleh Winbinder.
  • Walaupun Microsoft tidak menghentikan dukungan atas COM, teknologi tersebut sudah kadaluarsa dan kini digantikan oleh penerusnya.  Ingin beralih ke .NET?  Pelajari lebih lanjut tentang .NET Component.