2010-01-21 28 views
6

Sử dụng ATL (VS2008) làm thế nào tôi có thể liệt kê các phương thức khả dụng có sẵn trên giao diện IDispatch đã cho (IDispatch*)? Tôi cần phải tìm kiếm một phương thức có tên cụ thể và khi tôi có DISPID, hãy gọi phương thức (Tôi biết các tham số mà phương thức nhận được.) Lý tưởng nhất là tôi muốn thực hiện điều này bằng cách sử dụng con trỏ COM thông minh (CComPtr<>).Liệt kê các phương thức COM (IDispatch) bằng cách sử dụng ATL?

Điều này có khả thi không?

+1

thấy công cụ (mã nguồn) này: http://sourceforge.net/projects/axfuzz/files/ – lsalamon

+0

và điều này: http://www.codeproject.com/KB/atl/ienum.aspx – lsalamon

+0

Tôi đã đi tìm các ví dụ khác và cũng tìm thấy http://spec.winprog.org/typeinf2/ –

Trả lời

7

Bạn không thể liệt kê tất cả các phương thức có sẵn trừ khi đối tượng triển khai IDispatchEx.

Tuy nhiên, nếu bạn biết tên của phương thức bạn muốn gọi, bạn có thể sử dụng GetIDsOfNames để ánh xạ tên tới đúng DISPID.

HRESULT hr; 
CComPtr<IDispatch> dispatch; 
DISPID dispid; 
WCHAR *member = "YOUR-FUNCTION-NAME-HERE"; 
DISPPARAMS* dispparams; 

// Get your pointer to the IDispatch interface on the object here. Also setup your params in dispparams. 

hr = dispatch->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid); 
if (SUCCEEDED(hr)) { 
    hr = dispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, dispparams, &varResult, NULL, NULL); 
} 

Edit: Để hoàn chỉnh, tôi nghi ngờ có một cách để thẩm vấn các giao diện ITypeInfo2 (giả sử có một loại thư viện cho các đối tượng) mà bạn nhận được từ IDispatch :: GetTypeInfo cho một danh sách các phương pháp, nhưng tôi đã không thực hiện nó. Xem câu trả lời khác.

+0

Brilliant! Đúng thứ tôi cần. Cảm ơn rất nhiều. – Rob

+1

Tôi tin rằng tôi đã thực hiện mọi điểm bạn vừa đưa ra trong nhận xét của mình trong câu trả lời của tôi. Vui lòng đọc kỹ lại. Hơn nữa, tấm áp phích chỉ muốn có thể gọi một phương pháp mà anh ta đã biết tên. Vì vậy, câu trả lời của tôi đã cung cấp giải pháp cho những gì anh thực sự muốn làm, không nhất thiết là những gì anh ta hỏi. Đó là lý do tại sao, tôi nghi ngờ, nó đã được đánh dấu là câu trả lời đúng. Và cuối cùng, hãy bình tĩnh lại. Nó chỉ là 1s và 0s. –

15

Bạn có thể liệt kê các phương thức mà IDispatch hiển thị thông qua loại thông tin. Có hai cách để nhận thông tin loại:

Thật không may, việc triển khai IDispatch không bắt buộc phải cung cấp thông tin loại về các phương pháp và thuộc tính mà nó triển khai.

Nếu có, tuy nhiên, liệt kê cơ bản liên quan đến việc gọi ITypeInfo::GetTypeAttr để có được những TYPEATTR cho giao diện và nhìn vào số lượng các phương pháp thực hiện (cFuncs) và các biến (cVars) và Looping trên những điều này và kêu gọi ITypeInfo::GetFuncDesc() hoặc ITypeInfo::GetVarDesc(). Tất nhiên, có rất nhiều chi tiết bạn sẽ phải đối phó với như tôi có thể liệt kê ở đây, nhưng điều này nên là một điểm khởi đầu tốt cho thăm dò của bạn.

Đây là số article explaining the process in more details đẹp bằng mã trong VB.Net.

+0

Nội dung hay. Cảm ơn bạn đã thêm điều này. –

+0

@Franci, khi một thuộc tính là một mảng, VARDESC trả lại có một varkind = IDispatch. Làm thế nào bạn có thể cho biết liệu một thuộc tính là một mảng hay không, và nếu một mảng - làm thế nào tôi có thể truy cập các thành viên của nó? Khi gọi Invoke để lấy một mảng, kết quả là IDispatch. IDispatch này không hỗ trợ 'Item' hoặc 'Length' hoặc bất kỳ thuộc tính tương tự nào. – Uri

+1

@Uri - lưu ý rằng các thuộc tính không phải là các trường và cần được kiểm tra thông qua 'GetFuncDesc()' cung cấp cho bạn một 'FUNCDESC', từ đó bạn phải đi đến' elemdescFunc' (cho trả về) hoặc 'lprgelemdescParam' (cho thông số). Mảng thường được trả về như tham số ngoài, vì vậy bạn nên kiểm tra thứ hai. Trong mọi trường hợp, cả hai cái này đều cung cấp 'ELEMDESC', nơi bạn nên kiểm tra' tdesk', trả về cho bạn một 'TYPEDESC', dựa trên' VARTYPE vt' có thể thực ra là một 'ARRAYDESC'. Nếu đúng như vậy, bạn có 'SAFEARRAY'. –

10

Dưới đây là một số mã thực hiện liệt kê (nó chèn các cặp [Dispatch ID] - [Method Name] trong một bản đồ, nhưng điều đó dễ thay đổi).

/// 
/// \brief Returns a map of [DispId, Method Name] for the passed-in IDispatch object 
/// 
HRESULT COMTools::GetIDispatchMethods(_In_ IDispatch * pDisp, 
             _Out_ std::map<long, std::wstring> & methodsMap) 
{ 
    HRESULT hr = S_OK; 

    CComPtr<IDispatch> spDisp(pDisp); 
    if(!spDisp) 
     return E_INVALIDARG; 

    CComPtr<ITypeInfo> spTypeInfo; 
    hr = spDisp->GetTypeInfo(0, 0, &spTypeInfo); 
    if(SUCCEEDED(hr) && spTypeInfo) 
    { 
     TYPEATTR *pTatt = nullptr; 
     hr = spTypeInfo->GetTypeAttr(&pTatt); 
     if(SUCCEEDED(hr) && pTatt) 
     { 
      FUNCDESC * fd = nullptr; 
      for(int i = 0; i < pTatt->cFuncs; ++i) 
      { 
       hr = spTypeInfo->GetFuncDesc(i, &fd); 
       if(SUCCEEDED(hr) && fd) 
       { 
        CComBSTR funcName; 
        spTypeInfo->GetDocumentation(fd->memid, &funcName, nullptr, nullptr, nullptr); 
        if(funcName.Length()>0) 
        { 
         methodsMap[fd->memid] = funcName; 
        } 

        spTypeInfo->ReleaseFuncDesc(fd); 
       } 
      } 

      spTypeInfo->ReleaseTypeAttr(pTatt); 
     } 
    } 

    return hr; 

} 
+0

Tuyệt vời! mã này hoạt động liền mạch – Elmue

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