求教: Idispatch::invoke 内部实现原理 比如函数指针调用,需要有函数原型,传入参数才能使用。 我觉得,函数原型COM不可能提前知道的啊 。如果在编译类型库的时候确定,难道COM的源代码能实现自动编码? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 DISPPARAMS* pdispparams 不就是参数么 是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的? 是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?不需要知道啊,把参数压栈就行了。出错是调用者的问题。 Invoke参数说明:1. DISPID dispIdMember : 标志客户待调用的函数名,可由GetIDsOfNames获得2. REFIID riid : 必须为 IID_NULL3. LCID lcid : 用户本地化信息,可用 GetUserDefaultLCID() 获取4. WORD wFlags : 一个函数名称其实可以和四个函数关联 (常规函数,设置属性函数,通过引用设置属性函数,获取属性函数), 它的值可以是DISPATCH_METHOD, DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF, DISPATCH_PROPERTYGET.5. DISPPARAMS *pDispParams : 参数列表,其定义如下:[cpp] view plaincopytypedef struct tagDISPPARAMS { /* [size_is] */ VARIANTARG *rgvarg; //与VARIANT相同. 所以自动控制程序能支持的类型有限 /* [size_is] */ DISPID *rgdispidNamedArgs; //命名参数,C++中不用,VB支持 UINT cArgs; //参数个数 UINT cNamedArgs; } DISPPARAMS; 6. VARIANT *pVarResult :保存函数或propget的结果,没有返回值时为NULL7. EXCEPINFO *pExcepInfo :保存例外情况的信息,可参考C++异常处理。当Invoke返回DISP_E_EXCEPTION,DISP_E_PARAMNOTFOUND等 时,可查询pExcepInfo中相关信息。 是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的? 不使用C代码编译,是不是意味着COM调用的相关部分是汇编码搞定的么? 我很难理解,不需要源码即可调用的机制,能不能介绍一下 是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?这个实现不在ATL里面内嵌汇编是最简单的实现方式了。push ..push ..call .. 是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?这个实现不在ATL里面内嵌汇编是最简单的实现方式了。push ..push ..call ..多谢 微软的一个例子中的 Invoke 实现STDMETHODIMPCPoly::Invoke( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, unsigned int* puArgErr){ HRESULT hresult; VARIANTARG varg0, varg1; VARIANT varResultDummy; UNUSED(lcid); UNUSED(pexcepinfo); if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) return E_INVALIDARG; // this object only exposes a "default" interface. // if(!IsEqualIID(riid, IID_NULL)) return DISP_E_UNKNOWNINTERFACE; // This makes the following code a bit simpler if the caller // happens to be ignoring the return value. Some implementations // may choose to deal with this differently. // if(pvarResult == (VARIANT*)NULL) pvarResult = &varResultDummy; VariantInit(&varg0); VariantInit(&varg1); // assume the return type is void, unless we find otherwise. VariantInit(pvarResult); switch(dispidMember){ case IDMEMBER_CPOLY_DRAW: Draw(); break; case IDMEMBER_CPOLY_RESET: Reset(); break; case IDMEMBER_CPOLY_DUMP: Dump(); break; case IDMEMBER_CPOLY_QUIT: Quit(); break; case IDMEMBER_CPOLY_ADDPOINT: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; hresult = DispGetParam(pdispparams, 1, VT_I2, &varg1, puArgErr); if(hresult != NOERROR) return hresult; hresult = AddPoint(V_I2(&varg1), V_I2(&varg0)); if(hresult != NOERROR) return hresult; break; case IDMEMBER_CPOLY_ENUMPOINTS: IEnumVARIANT* penum; hresult = EnumPoints(&penum); if(hresult != NOERROR) return hresult; V_VT(pvarResult) = VT_UNKNOWN; hresult = penum->QueryInterface( IID_IUnknown, (void**)&V_UNKNOWN(pvarResult)); if(hresult != NOERROR) return hresult; penum->Release(); break; case IDMEMBER_CPOLY_GETXORIGIN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = m_xorg; break; case IDMEMBER_CPOLY_SETXORIGIN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; m_xorg = V_I2(&varg0); break; case IDMEMBER_CPOLY_GETYORIGIN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = m_yorg; break; case IDMEMBER_CPOLY_SETYORIGIN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; m_yorg = V_I2(&varg0); break; case IDMEMBER_CPOLY_GETWIDTH: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = GetWidth(); break; case IDMEMBER_CPOLY_SETWIDTH: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; SetWidth(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETRED: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_red(); break; case IDMEMBER_CPOLY_SETRED: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_red(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETGREEN: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_green(); break; case IDMEMBER_CPOLY_SETGREEN: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_green(V_I2(&varg0)); break; case IDMEMBER_CPOLY_GETBLUE: V_VT(pvarResult) = VT_I2; V_I2(pvarResult) = get_blue(); break; case IDMEMBER_CPOLY_SETBLUE: hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr); if(hresult != NOERROR) return hresult; set_blue(V_I2(&varg0)); break; default: return DISP_E_MEMBERNOTFOUND; } return NOERROR;} 是的,这也是我的疑问,上面代码用到的函数都是已知的,然而,我们写的函数原型对COM来说是未知的,这就是问题所在。 所以, 内部用汇编直接压栈比较合理 第一个,IDispatch所支持的数据类型是有限的第二个,IDispatch的实现需要事先有typelib 新手请教Picture控件打开jpg 如何使子对话框能透明显示他父窗口上的内容 多文档 如何同时打开并显示多个图像 修改视类的窗口类?? 大家帮我看看 下面代码有什么问题。是关于数据库查询的一些疑问 请教tab控件嵌套问题 鼠标与图标叠加的难题 如何写一个桌面程序 寻算法!! 请问高手们怎样才能将子对话框里的变量传回上一级对话框内 图像的模糊阈值分割算法的设计与实现 请问一下关于USB通讯监控的实现
不需要知道啊,把参数压栈就行了。出错是调用者的问题。
1. DISPID dispIdMember : 标志客户待调用的函数名,可由GetIDsOfNames获得
2. REFIID riid : 必须为 IID_NULL
3. LCID lcid : 用户本地化信息,可用 GetUserDefaultLCID() 获取
4. WORD wFlags : 一个函数名称其实可以和四个函数关联 (常规函数,设置属性函数,通过引用设置属性函数,获取属性函数),
它的值可以是DISPATCH_METHOD, DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF, DISPATCH_PROPERTYGET.
5. DISPPARAMS *pDispParams : 参数列表,其定义如下:[cpp] view plaincopy
typedef struct tagDISPPARAMS
{
/* [size_is] */ VARIANTARG *rgvarg; //与VARIANT相同. 所以自动控制程序能支持的类型有限
/* [size_is] */ DISPID *rgdispidNamedArgs; //命名参数,C++中不用,VB支持
UINT cArgs; //参数个数
UINT cNamedArgs;
} DISPPARAMS; 6. VARIANT *pVarResult :保存函数或propget的结果,没有返回值时为NULL
7. EXCEPINFO *pExcepInfo :保存例外情况的信息,可参考C++异常处理。当Invoke返回DISP_E_EXCEPTION,DISP_E_PARAMNOTFOUND等
时,可查询pExcepInfo中相关信息。
不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?
不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?
这个实现不在ATL里面内嵌汇编是最简单的实现方式了。
push ..
push ..
call ..
不需要知道啊,把参数压栈就行了。出错是调用者的问题。你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?
这个实现不在ATL里面内嵌汇编是最简单的实现方式了。
push ..
push ..
call ..
多谢
CPoly::Invoke(
DISPID dispidMember,
REFIID riid,
LCID lcid,
unsigned short wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
unsigned int* puArgErr)
{
HRESULT hresult;
VARIANTARG varg0, varg1;
VARIANT varResultDummy; UNUSED(lcid);
UNUSED(pexcepinfo); if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
return E_INVALIDARG; // this object only exposes a "default" interface.
//
if(!IsEqualIID(riid, IID_NULL))
return DISP_E_UNKNOWNINTERFACE; // This makes the following code a bit simpler if the caller
// happens to be ignoring the return value. Some implementations
// may choose to deal with this differently.
//
if(pvarResult == (VARIANT*)NULL)
pvarResult = &varResultDummy; VariantInit(&varg0);
VariantInit(&varg1); // assume the return type is void, unless we find otherwise.
VariantInit(pvarResult); switch(dispidMember){
case IDMEMBER_CPOLY_DRAW:
Draw();
break; case IDMEMBER_CPOLY_RESET:
Reset();
break; case IDMEMBER_CPOLY_DUMP:
Dump();
break; case IDMEMBER_CPOLY_QUIT:
Quit();
break; case IDMEMBER_CPOLY_ADDPOINT:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult; hresult = DispGetParam(pdispparams, 1, VT_I2, &varg1, puArgErr);
if(hresult != NOERROR)
return hresult; hresult = AddPoint(V_I2(&varg1), V_I2(&varg0));
if(hresult != NOERROR)
return hresult;
break; case IDMEMBER_CPOLY_ENUMPOINTS:
IEnumVARIANT* penum; hresult = EnumPoints(&penum);
if(hresult != NOERROR)
return hresult; V_VT(pvarResult) = VT_UNKNOWN;
hresult = penum->QueryInterface(
IID_IUnknown, (void**)&V_UNKNOWN(pvarResult));
if(hresult != NOERROR)
return hresult;
penum->Release();
break; case IDMEMBER_CPOLY_GETXORIGIN:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = m_xorg;
break; case IDMEMBER_CPOLY_SETXORIGIN:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
m_xorg = V_I2(&varg0);
break; case IDMEMBER_CPOLY_GETYORIGIN:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = m_yorg;
break; case IDMEMBER_CPOLY_SETYORIGIN:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
m_yorg = V_I2(&varg0);
break; case IDMEMBER_CPOLY_GETWIDTH:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = GetWidth();
break; case IDMEMBER_CPOLY_SETWIDTH:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
SetWidth(V_I2(&varg0));
break; case IDMEMBER_CPOLY_GETRED:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = get_red();
break; case IDMEMBER_CPOLY_SETRED:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
set_red(V_I2(&varg0));
break; case IDMEMBER_CPOLY_GETGREEN:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = get_green();
break; case IDMEMBER_CPOLY_SETGREEN:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
set_green(V_I2(&varg0));
break; case IDMEMBER_CPOLY_GETBLUE:
V_VT(pvarResult) = VT_I2;
V_I2(pvarResult) = get_blue();
break; case IDMEMBER_CPOLY_SETBLUE:
hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);
if(hresult != NOERROR)
return hresult;
set_blue(V_I2(&varg0));
break; default:
return DISP_E_MEMBERNOTFOUND;
} return NOERROR;
}
第二个,IDispatch的实现需要事先有typelib