DISPPARAMS* pdispparams 不就是参数么
是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?
不需要知道啊,把参数压栈就行了。出错是调用者的问题。
在类型库中会知道每一个参数。
然后,把这些参数构造调用堆栈,然后,直接呼叫。
不使用C代码编译。
DISPPARAMS* pdispparams 不就是参数么
是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?
不需要知道啊,把参数压栈就行了。出错是调用者的问题。
你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?
DISPPARAMS* pdispparams 不就是参数么
是参数,解析出参数,调用函数指针,那“函数原型” COM是如何提前预知的?
不需要知道啊,把参数压栈就行了。出错是调用者的问题。
你是说,有这样的API函数么? 不需要函数声明直接压栈的。 或者是,ATL直接使用汇编码搞定的?
这个实现不在ATL里面
内嵌汇编是最简单的实现方式了。
push ..
push ..
call ..
STDMETHODIMP
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;
}
微软的一个例子中的 Invoke 实现
STDMETHODIMP
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;
}