(91) 350-9520 support@omarine.org M-F: 7 AM - 7 PM; Weekends: 9 AM - 5 PM

Sử dụng các mã C++ để host trực tiếp các đối tượng COM

Nếu bạn thích thú viết mã C++ thì đó là điều tuyệt vời. Ngay cả như vậy, bạn đừng bỏ qua công cụ lập trình. Công cụ lập trình là giải pháp tự động hóa theo tiêu chuẩn thống nhất để giải quyết các vấn đề quen thuộc đảm bảo nhanh, khối lượng lớn và nhiều người có thể tham gia.

Trong ít trường hợp, một sản phẩm phần mềm chuyên biệt đòi hỏi nét nghệ thuật tinh tế với những yêu cầu ngoại lệ(exception) thì phải cần đến C++ ở dạng Native C++(hiểu là mã C++ tự nhiên, mã gốc để phân biệt với C++ nằm trong một công cụ lập trình).

Trong bài này chúng ta biểu diễn các hàm của thư viện COM để làm ví dụ.

Tạo ra đối tượng COM cụ thể dựa vào nhận dạng lớp

HRESULT hr; // Biến hr dùng để nhận kết quả trả về của hàm

_Application *papp=0; // papp là con trỏ giao diện _Application

CLSID clsid; // ID lớp của đối tượng Application

IUnknown *punk=0; // IUnknown của đối tượng Application

// Thu được nhận dạng lớp từ ProgID ứng với đối tượng Application của Excel

hr = CLSIDFromProgID(L“Excel.Application”, &clsid);

// Tạo đối tượng Application

hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,

IID_IUnknown, (void **)&punk);

// Yêu cầu giao diện _Application, IID__Application là GUI của giao diện này

hr = punk->QueryInterface(IID__Application, (void **)&papp);

// Giảm đếm tham chiếu đối tượng và rời bỏ con trỏ IUnknown

punk->Release();

Hàm CLSIDFromProgID tìm CLSID của đối tượng Application của Excel mà kết hợp với ProgID(programmatic identifier- nhận dạng chương trình) với giá trị L“Excel.Application”(L chỉ cho trình biên dịch biết đây là xâu kí tự rộng 2 byte, xâu kí tự Unicode UTF-16) trong cơ sở dữ liệu đăng kí của Windows(Windows registry). Bạn có thể tìm thấy GUI này trong registry với giá trị “{00024500-0000-0000-C000-000000000046}”. Trong trường hợp GUI này đã biết trước, chúng ta không phải dùng hàm CLSIDFromProgID nữa, cũng không cần biết ProgID, mà sử dụng hàm chuyển đổi UuidFromString như sau:

RPC_WSTR clsidStr=(RPC_WSTR)L“00024500-0000-0000-C000-000000000046”;

UuidFromString(clsidStr,&clsid);

RPC_WSTR là kiểu dữ liệu được định nghĩa có kiểu unsigned short*

Hàm CoCreateInstance tạo đối tượng Application theo clsid vừa đạt được. Tham số thứ ba CLSCTX_INPROC_SERVER xác định đối tượng COM tạo ra trong tiến trình của chương trình. IID_IUnknown là GUI của giao diện IUnknown- đây là giao diện cơ sở có trong mọi đối tượng COM. Hàm đạt được con trỏ của IUnknown là punk. punk sử dụng hàm QueryInterface để yêu cầu giao diện _Application với con trỏ papp. Con trỏ punk dùng hàm Release để giảm đếm tham chiếu và rời khỏi đối tượng. Hàm Release thực hiện trên tham chiếu cuối cùng sẽ giải phóng hoàn toàn đối tượng.

Lập trình Container

Một chương trình Container phải thi hành giao diện IOleClientSite và các giao diện khác. Bạn cần định nghĩa một lớp thi hành các giao diện này có dạng

class MyContainerClass :

public IOleClientSite,

public IOleInPlaceSite,

public ……………

{

public:

MyContainerClass (void);

~MyContainerClass(void);

// Các thuộc tính và phương thức ở đây

……………

}

Sau đó tạo một đối tượng lớp này

MyContainerClass MyContainerObject;

Lồng ghép OLE

CComPtr<IOleObject> spOleObj;

CComPtr là một lớp khuôn mẫu của ATL(Active Template Library) dùng để tạo con trỏ thông minh để quản lý con trỏ giao diện COM, trường hợp này mẫu là giao diện IOleObject. Con trỏ thông minh giúp đếm tham chiếu tự động để chống rò rỉ bộ nhớ.

Bây giờ dùng con trỏ giao diện papp của đối tượng Application để yêu cầu giao diện IOleObject

papp->QueryInterface(IID_IOleObject, (void**)&spOleObj);

Đặt site khách

spOleObj->SetClientSite(&MyContainerObject);

Lấy tọa độ cửa sổ chương trình

RECT rcClient; // rcClient là một biến RECT lưu giữ tọa độ hình chữ nhật vùng client của cửa sổ

GetClientRect(hWnd,&rcClient); // hWnd là handle của cửa sổ chương trình

Kích hoạt đối tượng tại chỗ ngay trong cửa sổ chương trình của bạn

spOleObj->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL,&MyContainerObject, 0, hWnd, &rcClient);

Truy cập thuộc tính đối tượng Automation bằng cách truy cập trực tiếp giao diện

Một khi đạt được con trỏ giao diện _Application, bạn có thể truy cập trực tiếp giao diện này để truy cập các thuộc tính và phương thức của đối tượng Application. Khi xử lý trực tiếp đối tượng COM thì tất cả đều là phương thức(hay hàm), nhưng ở góc độ công cụ lập trình thì phân ra thuộc tính và phương thức trong đó phương thức thì thực hiện những thao tác thuần túy, còn thuộc tính là các thành phần dữ liệu của đối tượng ứng với hai phương thức nhận giá trị(get) và đặt giá trị(put). Ví dụ chúng ta sử dụng phương thức nhận get_Workbooks của giao diện _Application để đạt được con trỏ tới giao diện Workbooks của đối tượng Workbooks, là một thuộc tính của đối tượng Application. Đối tượng Workbooks là một đối tượng tập hợp (hay danh sách) các đối tượng Workbook đang mở trong Excel.

Workbooks* wbs=0;

papp->get_Workbooks(&wbs);

Như vậy chúng ta đã đạt được con trỏ wbs của giao diện Workbooks.

Truy cập thuộc tính đối tượng Automation thông qua tên thuộc tính

Trên đây là cách chúng ta truy cập trực tiếp giao diện _Application. Bây giờ chúng ta truy cập đối tượng Application theo tên thuộc tính, không cần yêu cầu giao diện _Application nữa. Dòng mã xuất hiện trên phía đầu bài như thế này

hr = punk->QueryInterface(IID__Application, (void **)&papp);

sẽ bỏ đi. Thay vào đó chúng ta yêu cầu giao diện IDispatch

hr = punk->QueryInterface(IID_IDispatch, (void **)&pdisp);

Trước đó chúng ta phải khai báo thêm một số biến

IDispatch* wbsIdispatch=0, *pdisp=0; // Các con trỏ IDispatch

DISPID dispid; // Số nhận dạng thuộc tính

OLECHAR FAR* szMember = L“Workbooks”;// Tên thuộc tính là “Workbooks”

DISPPARAMS dispparams={0,0,0,0}; // Cấu trúc tham số, khởi tạo đều bằng 0 vì phương thức get không dùng đến

VARIANT wbsVariant; // Biến VARIANT chứa kết quả

Bây giờ lấy số nhận dạng thuộc tính theo tên

pdisp->GetIDsOfNames(

IID_NULL, &szMember,1,

LOCALE_USER_DEFAULT,&dispid);

Hàm này cho kết quả trong dispid, làm tham số cho hàm Invoke

pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_USER_DEFAULT,

DISPATCH_PROPERTYGET,

&dispparams, &wbsVariant, NULL, NULL);

Chúng ta được kết quả một con trỏ IDispatch trong biến wbsVariant

wbsIdispatch=wbsVariant.pdispVal;

// Yêu cầu giao diện Workbooks, IID_Workbooks là GUI của giao diện này

wbsIdispatch->QueryInterface(IID_Workbooks,(void**)&wbs);

pdisp->Release();

wbsIdispatch->Release();

Cuối cùng chúng ta cũng đạt được con trỏ wbs của giao diện Workbooks, mà không cần yêu cầu giao diện _Application.

Advertisements

Gửi phản hồi

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: