2011-01-10 2 views
5

Câu hỏi của tôi tương tự như Getting CLSID for a DLL file?, tôi nghĩ vậy.Cho COM DLL, trích xuất tất cả các lớp CLSID và tên giao diện tương ứng

Tôi có một thư mục với một số tệp DLL, mỗi tệp thực hiện một hoặc nhiều giao diện COM. Tôi muốn nhận được:

1) Mỗi ​​tên giao diện 2) CLSID của lớp thực hiện các giao diện

Đối với mỗi DLL. Điều quan trọng là mọi thứ có thể được thực hiện theo chương trình (Vì vậy, tôi không thể sử dụng một số loại trình duyệt COM và tự tìm kiếm thông tin đó).

Sau đó, tôi sẽ tra cứu CLSID cho tên giao diện và gọi một số phương thức bằng IDispatch.

Một thay thế có vẻ là quét sổ đăng ký cố gắng khớp với loại, giao diện và lớp GUID và tên tệp .dll. Nhưng điều đó có vẻ chậm và không mạnh mẽ.

Có ai đó có giải pháp rõ ràng cho vấn đề này không?

EDIT:

Với phản ứng của Ben Voigt, tôi đi kèm với đoạn mã sau đó phù hợp với nhu cầu của tôi:

ITypeLib *typelib; 
ITypeInfo *typeinfo; 
LoadTypeLibEx(_T("c:\\mydir\\mycom1"), REGKIND_NONE, &typelib); 
for (UINT i = 0;i < typelib->GetTypeInfoCount();++i) { 
    TYPEKIND typekind; 
    typelib->GetTypeInfoType(i, &typekind); 
    if (typekind == TKIND_COCLASS) { 
     // class! 
     CComBSTR className; 
     TYPEATTR *typeattr; 
     typelib->GetTypeInfo(i, &typeinfo); 
     typeinfo->GetDocumentation(MEMBERID_NIL, &className, NULL, NULL, NULL); 
     typeinfo->GetTypeAttr(&typeattr); 
     GUID classGUID = typeattr->guid; 
     for (UINT j = 0;j < typeattr->cImplTypes;++j) { 
      // interface! 
      CComBSTR interfaceName; 
      HREFTYPE hreftype; 
      ITypeInfo *classtypeinfo; 
      typeinfo->GetRefTypeOfImplType(j, &hreftype); 
      typeinfo->GetRefTypeInfo(hreftype, &classtypeinfo); 
      classtypeinfo->GetDocumentation(MEMBERID_NIL, &interfaceName, NULL, NULL, NULL); 
      // associate interfaceName with classGUID here 
     } 
    } 
} 

Trả lời

7

Bạn không thể nhận được rằng từ COM DLL, nhưng bạn có thể nhận được nó từ typelib. Tôi khá chắc chắn trình biên dịch MIDL có một chuyển đổi để dịch ngược một typelib, nhưng phân tích cú pháp IDL sẽ không dễ dàng như việc sử dụng API TypeLib.

Để làm phức tạp các vấn đề, typelib thường được lưu trữ dưới dạng tài nguyên bên trong DLL. Vì vậy, bạn sẽ trích xuất tài nguyên và mở nó bằng API TypeLib.

Bắt đầu với LoadTypeLibEx sẽ trả về con trỏ giao diện ITypeLib* (bạn biết bạn sẽ cần COM để nhận thông tin về thư viện COM, phải không?). Điều này thực sự sẽ thực hiện bước trích xuất tài nguyên cho bạn.

Sau đó, gọi ITypeLib::GetTypeInfoCount để tìm hiểu xem có bao nhiêu loại. Gọi ITypeLib::GetTypeInfoType cho mỗi người để tìm các giao diện và coclasses. Và gọi ITypeLib::GetTypeInfo, sau đó là ITypeInfo::GetDocumentation để lấy tên.

Dường như bạn có tất cả những điều này cho đến thời điểm này. Tiếp theo, bạn cần GUID của loại, được nhận với ITypeInfo::GetTypeAttr (không phải ITypeLib::GetLibAttr). Điều đó cung cấp cho bạn cấu trúc TYPEATTR, có trường guid.

Từ cùng một cấu trúc TYPEATTR, bạn sẽ cần trường cImplTypes. Điều đó cùng với ITypeInfo::GetRefTypeOfImplType sẽ cho phép bạn so khớp từng cốc với các giao diện mà nó thực hiện.

Lưu ý rằng không đảm bảo được mối quan hệ 1: 1 giữa giao diện và coc thực hiện. Và giao diện có thể nằm trong một thư viện khác từ chiếc cốc.

4

Rất ít cảnh báo về câu trả lời của Ben Voigt: không phải mọi DLL COM đều có typelib. Trong trường hợp của bạn, có vẻ như, nó có; nhưng đó không phải là một yêu cầu. Yêu cầu duy nhất của đá là DLL xuất hàm DllGetClassObject(), nơi bạn truyền một CLSID và lấy lại một nhà máy đối tượng.

Bạn có thể tải thư viện và gọi DllGetClassObject cho mọi CLSID đã đăng ký trên hệ thống (quét đăng ký theo HKCR \ CLSID để biết danh sách). Những người mà bạn nhận được một đối tượng hợp lệ trở lại là những người mà DLL hỗ trợ. Bây giờ, về mặt lý thuyết, thậm chí không yêu cầu CLSID hỗ trợ DLL được đăng ký; Tôi có thể hình dung một DLL thực hiện các lớp đối tượng riêng tư mà chỉ máy khách dự định mới biết và không ai khác nên làm như vậy. Nhưng đây là một kịch bản rất, rất kỳ lạ; cho một điều, cơ chế COM thường xuyên của việc tìm kiếm đường dẫn DLL của CLSID sẽ phá vỡ cho những người. Khách hàng sẽ phải tải DLL trực tiếp.

Bạn cũng có thể quét sổ đăng ký cho CLSID nơi tệp DLL đang được xem xét được đăng ký dưới dạng InprocServer32; điều này, một lần nữa, sẽ phá vỡ trong trường hợp của các lớp học tư nhân. Bạn có thể thực hiện tìm kiếm đăng ký trong regedit, tìm kiếm dữ liệu. Ngoài ra, bạn sẽ phải đối phó với các vấn đề về tên tập tin, tên ngắn và dài, hardlinks, thay thế biến môi trường và vân vân. Vì vậy, tôi sẽ không khuyên bạn nên nó.

CHỈNH SỬA: chỉ cần nghĩ theo cách khác. Tải về Regmon, chạy nó và gọi regsvr32 trên DLL. Sau đó xem những gì CLSID được chạm vào.

+0

'DllGetClassObject' có thể có tác dụng phụ không mong muốn, vì vậy tôi không đề nghị này. Ngoài ra, nó hoàn toàn có thể có một sự kết hợp của CLSID công cộng và tư nhân. Kể từ khi DLL được nạp bằng cách tạo ra một loại công cộng, không cần phải bao giờ tải DLL bên ngoài cơ chế COM. –

+0

Vâng, pháp lý * cuối cùng * sẽ liên quan đến việc tháo DLL và đi qua mã của DllGetClassObject(). Trong việc thực hiện điển hình (đọc: một ATL) sẽ có một cấu trúc dữ liệu toàn cầu gọn gàng liệt kê tất cả các CLSID ở một nơi. Tôi khó có thể tưởng tượng một COM DLL nơi tập hợp các coclasses được hỗ trợ có điều kiện. –

+0

Nó phụ thuộc vào sơ đồ cấp phép lén lút như thế nào. Tôi chắc chắn có thể hình dung một yêu cầu để khởi tạo một đối tượng quản lý giấy phép và sử dụng nó trước khi bất kỳ lớp nào khác có thể được khởi tạo, câu hỏi là liệu sự thất bại từ việc cố tạo đối tượng không có giấy phép là "Tôi không biết đối tượng đó" hoặc "Đã thử để tạo ra đối tượng đó nhưng không thành công " –