Idispatch interfaces-getidsofnames and invoke

Source: Internet
Author: User

The idispatch interface is the core of COM automation. In fact, the idispatch interface is also very simple, there are only four methods:

    IDispatch : public IUnknown    {    public:        virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(             /* [out] */ __RPC__out UINT *pctinfo) = 0;                virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(             /* [in] */ UINT iTInfo,            /* [in] */ LCID lcid,            /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) = 0;                virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(             /* [in] */ __RPC__in REFIID riid,            /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,            /* [range][in] */ __RPC__in_range(0,16384) UINT cNames,            /* [in] */ LCID lcid,            /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) = 0;                virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke(             /* [annotation][in] */             _In_  DISPID dispIdMember,            /* [annotation][in] */             _In_  REFIID riid,            /* [annotation][in] */             _In_  LCID lcid,            /* [annotation][in] */             _In_  WORD wFlags,            /* [annotation][out][in] */             _In_  DISPPARAMS *pDispParams,            /* [annotation][out] */             _Out_opt_  VARIANT *pVarResult,            /* [annotation][out] */             _Out_opt_  EXCEPINFO *pExcepInfo,            /* [annotation][out] */             _Out_opt_  UINT *puArgErr) = 0;            };
Gettypeinfocount and gettypeinfo will be discussed later.

Let's take a look at the familiar getidsofnames and invoke.

Getidsofnames

The main function of this function is to map the method name and parameter (optional) of the COM interface into a set of dispid. Dispid is a long type:

typedef LONG DISPID;
Getidsofnames () can obtain methods and attributes. Let's look at an example. The COM interface imycar

[object,uuid(21B794E2-4857-4576-8FC2-CDAB2A486600),dual,nonextensible,pointer_default(unique)]interface IMyCar : IDispatch{    [id(1)] HRESULT Run();    [id(2)] HRESULT AddGas([in] LONG add, [out] LONG* total);    [propget, id(3)] HRESULT Gas([out, retval] LONG* pVal);};
This interface contains the addgas method, which has two parameters, one input and one output. Its implementation is basically as follows:

STDMETHODIMP CMyCar::AddGas(LONG add, LONG* total){    // TODO: Add your implementation code here    m_Gas += add;    *total = m_Gas;    return S_OK;}

Try to get the ID and index parameters of the addgas function. See the following code. The first element in the array is the method name, and the second/third element is the parameter name.

    CComPtr<IMyCar> spCar;    spCar.CoCreateInstance(CLSID_MyCar);

    DISPID PropertyID[3] = {0};    BSTR PropName[3];            PropName[0] = SysAllocString(L"AddGas");    PropName[1] = SysAllocString(L"add");    PropName[2] = SysAllocString(L"total");    HRESULT hr = spCar->GetIDsOfNames(IID_NULL, PropName, 3, LOCALE_SYSTEM_DEFAULT, PropertyID);    SysFreeString(PropName[0]);    SysFreeString(PropName[1]);    SysFreeString(PropName[2]);
Run the command to obtain the following results:

In the propertyid array, three values can be obtained: 2, 0, 1.

2 represents the ID of addgas, which is the same as that in the IDL file.

0 indicates that "add" is the first parameter, and 1 indicates that "Total" is the second parameter.

Invoke

Invoke is a very important and similar function in idispatch. method calls depend on this function. Function prototype:

HRESULT Invoke(  [in]       DISPID dispIdMember,  [in]       REFIID riid,  [in]       LCID lcid,  [in]       WORD wFlags,  [in, out]  DISPPARAMS *pDispParams,  [out]      VARIANT *pVarResult,  [out]      EXCEPINFO *pExcepInfo,  [out]      UINT *puArgErr);

For details about each parameter, refer to the following section from msdn.

Let's look at a call example:

    CComVariant avarParams[2];    avarParams[1].vt = VT_I4;    avarParams[1] = 4;    LONG vTotal = 0;    avarParams[0].vt = VT_I4 | VT_BYREF;    avarParams[0] = &vTotal;    DISPPARAMS params = { avarParams,        NULL,              // Dispatch identifiers of named arguments.         2,                 // Number of arguments.        0 };                // Number of named arguments.    hr = spCar->Invoke(PropertyID[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
Avarparams is an array with two elements. It indicates the parameters of the method to be called, Note that the parameters here are in reverse order.For example, avarparam [1] stores the first parameter as an input parameter, and avarparams [0] stores the second parameter as an output parameter.

Run:

The initial m_gas value in spcar is 0. When we add 4 to it during the call, the output should be 4. Check the above running result. vtotal is indeed 4.

In this way, the method of COM component is successfully called through invoke (instead of through spcar-> addgas ). Note that the first parameter in invoke is a dispid, which is from getidsofnames.


You can also use invoke to call the attributes of a COM object.

For example, the gas in the IDL above.

The Calling property is similar to the method. If we want to read an attribute, we can call it like this:

    DISPID PropertyID2[1] = { 0 };    BSTR PropName2[1];    PropName2[0] = SysAllocString(L"Gas");        hr = spCar->GetIDsOfNames(IID_NULL, PropName2, 1, LOCALE_SYSTEM_DEFAULT, PropertyID2);    SysFreeString(PropName2[0]);    DISPPARAMS params2 = { NULL,        NULL,        0,        0    };        CComVariant Result;    hr = spCar->Invoke(PropertyID2[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params2, &Result, NULL, NULL);    

Run the command to obtain the result:



Note,The fifth parameter of invoke is useless. The attribute value is returned from the sixth parameter. If it is a method call, the com method parameter needs to be passed in from the fifth parameter, and the sixth parameter is the return value of the function call hresult.

I have not tried the put attribute and do not know where to import it. Just check msdn when necessary.


The above are brief descriptions and examples of getidsofnames and invoke. Then we will analyze more details.

Complete client code:

// ConsoleApplication4.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <thread>#include <atlbase.h>#include <atlcom.h>#include <algorithm>#include <vector>#include <memory>#include "../MyCom/MyCom_i.h"#include "../MyCom/MyCom_i.c"int _tmain(int argc, _TCHAR* argv[]){    CoInitializeEx(NULL, COINIT_MULTITHREADED);        CComPtr<IMyCar> spCar;    spCar.CoCreateInstance(CLSID_MyCar);    // use IDispatch    DISPID PropertyID[3] = {0};    BSTR PropName[3];            PropName[0] = SysAllocString(L"AddGas");    PropName[1] = SysAllocString(L"add");    PropName[2] = SysAllocString(L"total");    HRESULT hr = spCar->GetIDsOfNames(IID_NULL, PropName, 3, LOCALE_SYSTEM_DEFAULT, PropertyID);    SysFreeString(PropName[0]);    SysFreeString(PropName[1]);    SysFreeString(PropName[2]);    CComVariant avarParams[2];    avarParams[1].vt = VT_I4;    avarParams[1] = 4;    LONG vTotal = 0;    avarParams[0].vt = VT_I4 | VT_BYREF;    avarParams[0] = &vTotal;    DISPPARAMS params = { avarParams,        NULL,              // Dispatch identifiers of named arguments.         2,                 // Number of arguments.        0 };                // Number of named arguments.    hr = spCar->Invoke(PropertyID[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);        DISPID PropertyID2[1] = { 0 };    BSTR PropName2[1];    PropName2[0] = SysAllocString(L"Gas");        hr = spCar->GetIDsOfNames(IID_NULL, PropName2, 1, LOCALE_SYSTEM_DEFAULT, PropertyID2);    SysFreeString(PropName2[0]);    DISPPARAMS params2 = { NULL,        NULL,        0,        0    };        CComVariant Result;    hr = spCar->Invoke(PropertyID2[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms2, &Result, NULL, NULL);        spCar.Release();    CoUninitialize();    return 0;}
Related COM component code:

STDMETHODIMP CMyCar::AddGas(LONG add, LONG* total){    // TODO: Add your implementation code here    m_Gas += add;    *total = m_Gas;    return S_OK;}STDMETHODIMP CMyCar::get_Gas(LONG* pVal){    // TODO: Add your implementation code here    *pVal = m_Gas;    return S_OK;}






Idispatch interfaces-getidsofnames and invoke

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.