首页 > com > com-IDispatch测试代码
2013一月5

com-IDispatch测试代码

[隐藏]

1.IDispatch 接口

Dispatch 接口需要实现4个函数,调用者只通过这4个函数,就能实现调用自动化组件中所有的函数。这4个函数功能如下:

HRESULT GetTypeInfoCount([out] UINT * pctinfo) 组件中提供几个类型库?当然一般都是一个啦。
但如果你在一个组件中实现了多个 
IDispatch 接口,那就不一定啦(注1)
HRESULT GetTypeInfo([in] UINT iTInfo,[in] LCID lcid,[out] ITypeInfo ** ppTInfo) 调用者通过该函数取得他想要的类型库。
幸好,在 99% 的情况下,我们都不用关心这两个函数的实现,因为 MFC/ATL 都帮我们完成了默认的一个实现,如果是自己完成函数代码,甚至可以直接返回 E_NOTIMPL 表示没有实现。(注2)
HRESULT GetIDsOfNames([in] REFIID riid,[in,size_is(cNames)] LPOLESTR * rgszNames,[in] UINT cNames,[in] LCID lcid,[out,size_is(cNames)] DISPID * rgDispId) 根据函数名称取得函数序号,为调用 Invoke() 做准备。
所谓函数序号,大家去观察双接口 IDL 文件和 MFC 的 ODL 文件,每一个函数和属性都会有
 [id(序号)….] 这样的描述。
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)
根据序号,执行函数。
使用 MFC/ATL 写的组件程序,我们也不必关心这个函数的实现。如果是自己写代码,则该函数类似如下实现:
switch(dispIdMember)
{
case 1: …..; break;
case 2: …..; break;
….
}其实,就是根据序号进行分支调用啦。(注3)

IDispatch接口是COM自动化的核心。其实,IDispatch这个接口本身也很简单,只有4个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    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;
 
    };

GetIDsOfNames
这个函数的主要功能就是:把COM接口的方法名字和参数(可选)映射成一组DISPID。DISPID就是一个LONG型:

1
typedef LONG DISPID;

GetIDsOfNames()可以获取方法和属性。先来看一个例子,COM接口IMyCar

1
2
3
4
5
6
7
8
9
10
11
12
[
	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);
};


这个接口里面有一个方法AddGas,它有两个参数,一个输入,一个输出。它的实现基本如下:

1
2
3
4
5
6
7
STDMETHODIMP CMyCar::AddGas(LONG add, LONG* total)
{
    // TODO: Add your implementation code here
    m_Gas += add;
    *total = m_Gas;
    return S_OK;
}


试试如何获取AddGas函数的id和参数index,看下面的代码。数组里面的第一个元素是方法名字,第二个/第三个是参数名字。

1
2
3
4
5
6
7
8
9
10
11
12
    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]);

运行一下,可以得到如下结果:

1.png

PropertyID数组里面可以得到3个值:2, 0, 1.

2代表的是AddGas的id,跟idl文件里面的一样。

0表示"add"是第一个参数,1表示"total"是第二个参数。
Invoke

Invoke是IDispatch里面非常重要的一样函数,方法调用就靠这个函数了。函数原型:

1
2
3
4
5
6
7
8
9
10
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
);

每一个参数的说明,看下面,从MSDN截来的

11.png

先来看一个调用例子:

1
2
3
4
5
6
7
8
9
10
11
    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是一个具有2个元素的数组,它表示要调用的方法的参数,注意这里的参数是逆序的。比如avarParam[1]存放的是第一个参数,是一个输入参数;avarParams[0]存放的是第二个参数,是一个输出参数。
运行一下:

12.png

spCar里面的m_Gas初始值是0,我们调用的时候给它加了4,那么输出就应该是4.看上面的运行结果,vTotal确实是4.

这样我们就通过Invoke成功调用了COM组件的方法(而不是通过spCar->AddGas)。注意Invoke里面的第一个参数是一个DISPID,这个是从GetIDsOfNames来的。
使用Invoke也可以调用COM对象的属性。

比如上面的idl里面的Gas。

调用属性跟方法差不多,如果我们想读取一个属性,那么可以这么调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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);

运行可以得到结果:

15.png

注意,Invoke的第五个参数啥都没,属性值是从第六个参数返回出来的。如果是方法调用的话,那么COM方法参数需要从第五个参数传进入,第六个参数是函数调用的返回值HRESULT.

我没有试过属性的put,不知道是从哪里传入,当有需要的时候查一下MSDN就行了。

以上就是GetIDsOfNames和Invoke的简要说明以及例子。之后再来分析更多的细节。

完整客户端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 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;
}

相关的COM组件的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

文章作者:hgy413
本文地址:https://hgy413.com/2006.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

26 Responses to “com-IDispatch测试代码”

  1. #1 minecraft 回复 | 引用 Post:2018-10-04 10:28

    What a stuff of un-ambiguity and preserveness of precious experience regarding unpredicted emotions.

  2. #2 minecraft 回复 | 引用 Post:2018-10-04 22:13

    I visit every day some web pages and information sites to read content,
    however this website gives quality based writing.

  3. #3 minecraft 回复 | 引用 Post:2018-10-07 06:24

    Wow that was strange. I just wrote an very long comment but after I clicked submit
    my comment didn’t show up. Grrrr… well I’m not writing all that over again. Anyways, just wanted
    to say wonderful blog!

  4. #4 minecraft 回复 | 引用 Post:2018-10-07 09:19

    Hi there, just became alert to your blog through
    Google, and found that it is truly informative.
    I’m gonna watch out for brussels. I will appreciate if you continue this in future.
    Many people will be benefited from your writing. Cheers!

  5. Hello this is kinda of off topic but I was wondering
    if blogs use WYSIWYG editors or if you have to
    manually code with HTML. I’m starting a blog soon but have no coding expertise so
    I wanted to get guidance from someone with experience. Any help would be greatly appreciated!

  6. Nice post. I was checking constantly this blog and I am impressed!
    Very useful info specially the closing section :
    ) I deal with such info much. I was seeking this certain information for a
    long time. Thanks and good luck.

  7. Hello, always i used to check website posts here
    early in the morning, because i like to gain knowledge of more and more.

  8. Hi there friends, its fantastic article regarding cultureand fully defined, keep
    it up all the time.

  9. Hey there, You’ve done a great job. I’ll certainly
    digg it and personally suggest to my friends. I am confident they will be benefited from this web
    site.

  10. #10 Coconut Oil Benefits 回复 | 引用 Post:2018-10-23 04:45

    That is very fascinating, You’re an excessively professional blogger.
    I have joined your feed and sit up for looking for extra
    of your excellent post. Also, I’ve shared your web site in my social networks

  11. Stunning story there. What happened after? Good luck!

  12. I was recommended this website by my cousin. I’m not
    sure whether this post is written by him as nobody else know such detailed about my difficulty.
    You are amazing! Thanks!

  13. I enjoy looking through a post that can make people think.
    Also, many thanks for allowing me to comment!

  14. #14 descargar facebook 回复 | 引用 Post:2018-11-02 08:45

    Heya i’m for the primary time here. I came across this board and I in finding
    It really useful & it helped me out much.
    I’m hoping to provide one thing again and
    aid others like you aided me.

  15. #15 quest bars 回复 | 引用 Post:2018-11-06 03:00

    Heya this is somewhat of off topic but I was wanting to know if blogs use WYSIWYG editors or if you have
    to manually code with HTML. I’m starting a blog soon but have no coding know-how so I wanted
    to get guidance from someone with experience.
    Any help would be enormously appreciated!

  16. Have you ever thought about creating an e-book or guest authoring on other sites?
    I have a blog centered on the same topics you discuss and would really
    like to have you share some stories/information. I know my subscribers would value
    your work. If you’re even remotely interested, feel free to send
    me an email.

  17. Please let me know if you’re looking for a author for your site.
    You have some really good articles and I think I would be a good asset.

    If you ever want to take some of the load off, I’d absolutely love to write some material for your blog in exchange for a link back to mine.
    Please shoot me an email if interested. Regards!

  18. It’s an remarkable paragraph for all the online viewers; they will take advantage from it I am sure.

  19. #19 Sling TV 回复 | 引用 Post:2018-11-14 08:36

    Hello, I do think your blog could possibly be having browser compatibility issues.
    When I take a look at your web site in Safari,
    it looks fine however, if opening in Internet Explorer, it’s got some overlapping issues.
    I just wanted to give you a quick heads up! Aside from that, wonderful
    site!

  20. #20 Sling TV 回复 | 引用 Post:2018-11-15 05:38

    It’s going to be finish of mine day, however before ending I am
    reading this enormous piece of writing to improve
    my knowledge.

  21. Wonderful goods from you, man. I have understand your stuff
    previous to and you are just extremely wonderful. I really like what you’ve
    acquired here, certainly like what you’re saying and the
    way in which you say it. You make it entertaining and you still care for to keep it wise.
    I can’t wait to read far more from you. This is really a tremendous website.

  22. Your means of explaining everything in this piece of writing is truly good, every one be able to
    easily be aware of it, Thanks a lot.

  23. #23 descargar facebook 回复 | 引用 Post:2018-12-06 08:06

    You’re so awesome! I don’t believe I have read something like that before.
    So great to find somebody with some genuine thoughts
    on this subject matter. Seriously.. thank you for starting this up.
    This site is something that is required on the web, someone with a little originality!

  24. #24 g use 回复 | 引用 Post:2020-06-10 12:30

    What’s up i am kavin, its my first time to commenting anyplace, when i read this article i
    thought i could also create comment due to this good
    post.

  25. #25 g for 回复 | 引用 Post:2020-06-11 01:42

    Hey there this is somewhat of off topic but I was wanting to know if
    blogs use WYSIWYG editors or if you have to manually
    code with HTML. I’m starting a blog soon but have no coding
    experience so I wanted to get advice from someone with experience.

    Any help would be greatly appreciated!

  26. #26 on g 回复 | 引用 Post:2020-06-11 16:51

    Hello! I’ve been following your web site for a long time now and finally got
    the bravery to go ahead and give you a shout out from Porter Texas!
    Just wanted to mention keep up the great job!

发表评论