2010-01-27 34 views
8

Tôi đang tìm cách triển khai thực hiện tùy chỉnh COM trong C++ trên nền tảng kiểu UNIX để cho phép tôi tải động và liên kết mã hướng đối tượng. Tôi nghĩ điều này sẽ dựa trên một bộ chức năng tương tự mà POSIX cung cấp để tải và gọi dll dlopen, dlsym và dlclose của dll.Triển khai COM tùy chỉnh?

Tôi hiểu rằng ý tưởng chung của COM là bạn liên kết đến một vài chức năng tức là QueryInterface, AddRef và Release trong một dll thông thường (Kernel32.dll), sau đó cho phép bạn truy cập các giao diện chỉ là một bảng con trỏ hàm được đóng gói với một con trỏ tới đối tượng mà các con trỏ hàm sẽ được gọi với. Các chức năng này được hiển thị thông qua IUnknown mà bạn phải kế thừa.

Vậy điều này hoạt động như thế nào? Có cách nào tốt hơn để liên kết động và tải tới mã định hướng đối tượng không? Làm thế nào để thừa kế từ một công việc dll - không phải mọi cuộc gọi đến lớp cơ sở phải được đến một thành viên tiếp xúc chức năng tức là/bảo vệ/công cộng chỉ đơn giản là bỏ qua?

Tôi khá thành thạo về C++ và lập trình meta mẫu và đã có hệ thống C++ hoàn toàn phản chiếu, các thuộc tính thành viên, hàm thành viên và chức năng toàn cục/tĩnh sử dụng tăng.

Trả lời

4

Tôi đang tìm cách triển khai thực hiện tùy chỉnh COM trong C++ trên nền tảng kiểu UNIX để cho phép tôi tải động và liên kết mã hướng đối tượng. Tôi nghĩ điều này sẽ dựa trên một bộ chức năng tương tự mà POSIX cung cấp để tải và gọi dll dlopen, dlsym và dlclose của dll.

Ở mức đơn giản nhất, COM được triển khai bằng giao diện. Trong C++, nếu bạn cảm thấy thoải mái với ý tưởng của lớp cơ sở ảo, hoặc trừu tượng thuần túy, sau đó bạn đã biết làm thế nào để xác định một giao diện trong C++

struct IMyInterface { 
    void Method1() =0; 
    void Method2() =0; 
}; 

Thời gian chạy COM cung cấp rất nhiều dịch vụ bổ sung mà áp dụng cho cửa sổ môi trường nhưng arn't thực sự cần thiết khi thực hiện "mini" COM trong một ứng dụng duy nhất như là một phương tiện để tự động liên kết đến một giao diện OO hơn truyền thống cho phép bởi dlopen, dlsym, vv

Các đối tượng COM được thực hiện trong .dll , .so hoặc .dylib tệp tùy thuộc vào nền tảng của bạn. Các tệp này cần phải xuất ít nhất một hàm được chuẩn hóa: DllGetClassObject

Trong môi trường của riêng bạn, bạn có thể tạo mẫu thử theo cách bạn muốn nhưng để interop với thời gian chạy COM trên cửa sổ rõ ràng tên và thông số cần phải tuân theo tiêu chuẩn com .

Ý tưởng cơ bản là, điều này được chuyển đến một GUID - 16 byte được gán cho một đối tượng cụ thể và tạo (dựa trên GUID) và trả về IClassFactory * của đối tượng nhà máy.

Đối tượng nhà máy sau đó được sử dụng, theo thời gian chạy COM, để tạo các cá thể của đối tượng khi phương thức IClassFactory :: CreateInstance được gọi.

Vì vậy, cho đến nay bạn có

  • một thư viện động xuất khẩu ít nhất một biểu tượng, tên là "DllGetClassObject" (hoặc một số biến thể của chúng)
  • phương pháp
  • Một DllGetClassObject để kiểm tra thông qua tại GUID để xem và đối tượng nào đang được yêu cầu và sau đó thực hiện một "CSomeObjectClassFactory" mới
  • Triển khai CSomeObjectClassFactory triển khai (bắt nguồn từ) IClassFactory và triển khai phương thức CreateInstance cho các phiên bản "mới" của CSupportedObject.
  • CSomeSupportedObject triển khai giao diện tùy chỉnh hoặc COM được xác định từ IUnknown. Điều này rất quan trọng vì IClassFactory :: CreateInstance được chuyển qua một IID (một lần nữa, một id duy nhất 16byte định nghĩa một giao diện lần này) rằng nó sẽ cần QueryInterface trên đối tượng.

Tôi hiểu rằng các ý tưởng chung của COM là bạn liên kết đến một vài chức năng tức là QueryInterface, AddRef và Thả trong một dll chung (Kernel32.dll) mà sau đó cho phép bạn truy cập giao diện mà chỉ là một bảng các con trỏ hàm được đóng gói với một con trỏ tới đối tượng mà các con trỏ hàm sẽ được gọi với. Các chức năng này được hiển thị thông qua IUnknown mà bạn phải kế thừa.

Thực ra, COM được thực hiện bởi OLE32.dll để hiển thị api "c" được gọi là CoCreateInstance. Các ứng dụng thông qua CoCreateInstance một GUID, mà nó nhìn lên trong cửa sổ đăng ký - trong đó có một DB của GUID -> "đường dẫn đến dll" ánh xạ. OLE/COM sau đó tải (dlopen) dll, gọi phương thức DllGetClassObject (dlsym) của nó, đi qua GUID một lần nữa, giả sử rằng thành công, OLE/COM sau đó gọi CreateInstance và trả về giao diện kết quả cho ứng dụng.

Vậy điều này hoạt động như thế nào? Có cách nào tốt hơn để liên kết động và tải tới mã định hướng đối tượng không? Làm thế nào để thừa kế từ một công việc dll - không phải mọi cuộc gọi đến lớp cơ sở phải được đến một thành viên tiếp xúc chức năng tức là/bảo vệ/công cộng chỉ đơn giản là bỏ qua?

Thừa kế ngầm mã C++ từ dll/so/dylib hoạt động bằng cách xuất mọi phương thức trong lớp dưới dạng biểu tượng "được trang trí". Tên phương thức được trang trí với lớp và loại của mọi tham số. Điều này cũng giống như cách các biểu tượng được xuất từ ​​các thư viện tĩnh (.a hoặc .lib files iirc). Thư viện tĩnh hoặc động, "riêng tư, được bảo vệ, v.v." luôn được thực thi bởi trình biên dịch, phân tích cú pháp các tệp tiêu đề, không bao giờ là trình liên kết.

Tôi khá thành thạo trong C++ và lập trình meta mẫu và đã có hệ thống C++ hoàn toàn phản chiếu, thuộc tính thành viên, hàm thành viên và chức năng toàn cục/tĩnh sử dụng tăng.

Các lớp C++ thường chỉ có thể được xuất từ ​​dll có liên kết tĩnh - dll được tải khi tải, không qua dlopen khi chạy. COM cho phép các giao diện C++ được nạp động bằng cách đảm bảo rằng tất cả các kiểu dữ liệu được sử dụng trong COM là các kiểu pod, hoặc là các giao diện ảo thuần túy.Nếu bạn phá vỡ quy tắc này, bằng cách định nghĩa một giao diện cố gắng vượt qua một tăng hoặc bất kỳ loại đối tượng nào khác, bạn sẽ nhanh chóng gặp phải tình huống mà trình biên dịch/trình liên kết sẽ cần nhiều hơn chỉ là tệp tiêu đề để tìm hiểu những gì đang diễn ra và dll "com" được chuẩn bị cẩn thận sẽ phải được liên kết tĩnh hoặc ngầm để hoạt động.

Quy tắc khác của COM là, không bao giờ chuyển quyền sở hữu đối tượng qua ranh giới thư viện động. tức là không bao giờ trả lại giao diện hoặc dữ liệu từ dll và yêu cầu ứng dụng xóa nó. Giao diện tất cả cần phải thực hiện IUnknown, hoặc ít nhất là một Release() phương pháp, cho phép các đối tượng để thực hiện xóa này. Bất kỳ kiểu dữ liệu trả về nào cũng phải có một trình phân bổ de-allocator nổi tiếng - nếu bạn có một giao diện với một phương thức được gọi là "CreateBlob", có lẽ nên có một phương thức bạn gọi là "DeleteBlob".

2

Để thực sự hiểu cách COM hoạt động, tôi khuyên bạn nên đọc "Essential COM" của Don Box.

3

Xem tài liệu CORBA, tại System.ComponentModel trong sscli, các phần XPCOM của bộ mã hóa Mozilla. Miguel de Icaza đã triển khai một cái gì đó giống như OLE trong GNOME được gọi là Bonobo cũng có thể hữu ích.

Tùy thuộc vào những gì bạn đang làm với C++, bạn có thể muốn xem các khuôn khổ plugin cho C++ như Yehia. Tôi tin rằng Boost cũng có một cái gì đó tương tự.

Chỉnh sửa: pugg dường như được duy trì tốt hơn Yehia tại thời điểm này. Tôi đã không thử nó mặc dù.

6

Một vài điều cần lưu ý:

  • Sức mạnh của COM đến chủ yếu từ IDL và trình biên dịch tức. Nó cho phép định nghĩa verry succint về các đối tượng và giao diện với tất cả các bản mẫu C/C++ được tạo ra cho bạn.

  • Đăng ký COM. Trên Windows, ID lớp (CLSID) được ghi lại trong sổ đăng ký nơi chúng được liên kết với tệp thực thi. Bạn phải cung cấp chức năng tương tự trong môi trường UNIX.

  • Việc triển khai IUnknown toàn bộ là khá tầm thường, ngoại trừ QueryInterface hoạt động khi được triển khai trong C (nghĩa là không có RTTI).

  • Một khía cạnh hoàn toàn khác của COM là IDispatch - tức là lời gọi và khám phá phương thức bị ràng buộc trễ (chỉ đọc phản chiếu).

Hãy xem XPCOM vì đây là môi trường COM đa nền tảng. Đây thực sự là một trong những điều bạn nên tận dụng các công nghệ khác. Nó có thể hút rất nhiều thời gian tốt hơn ở những nơi khác.

3

Thiết kế cơ bản của COM khá đơn giản.

  1. Tất cả các đối tượng COM tiếp xúc với chức năng của mình thông qua một hoặc nhiều giao diện
  2. Tất cả các giao diện có nguồn gốc từ giao diện IUnknown, do đó tất cả các giao diện có QueryInterface, AddRef & phương pháp phát hành là 3 phương pháp đầu tiên của chức năng ảo của họ bảng theo thứ tự đã biết
  3. Tất cả các đối tượng thực hiện IUnknown
  4. Bất kỳ giao diện nào hỗ trợ đối tượng đều có thể truy vấn từ bất kỳ giao diện nào khác.
  5. Giao diện được xác định bằng Số nhận dạng duy nhất trên toàn cầu, đây là các GUID hoặc CLSID của IID, nhưng tất cả chúng đều giống nhau. http://en.wikipedia.org/wiki/Globally_Unique_Identifier

Trường hợp COM phức tạp là cách giao dịch cho phép giao diện được gọi từ bên ngoài quá trình mà đối tượng cư trú. COM marshalling là một khó chịu, lông, con thú. Thực hiện nhiều hơn như vậy bởi thực tế là COM hỗ trợ cả hai mô hình lập trình đơn luồng và đa luồng.

Việc triển khai Windows cho phép các đối tượng được đăng ký (việc sử dụng ban đầu của sổ đăng ký Windows là dành cho COM). Ở mức tối thiểu, đăng ký COM chứa ánh xạ giữa GUID duy nhất cho đối tượng COM và thư viện (dll) chứa mã của nó.

Để làm việc này. Các DLL thực hiện các đối tượng COM phải có một ClassFactory - một điểm vào trong DLL với một tên tiêu chuẩn có thể được gọi để tạo ra một trong các đối tượng COM thực thi DLL. (Trong thực tế, Windows COM nhận một đối tượng IClassFactory từ điểm vào này và sử dụng nó để tạo các đối tượng COM khác).

vì vậy đó là chuyến đi 10 xu, nhưng để thực sự hiểu điều này, bạn cần phải đọc Essential COM bởi Don Box.

Các vấn đề liên quan