// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*-
//
// AcdkObjectpyright (C) 2000 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// ALL RIGHTS RESERVED
//
// This file is part of ACDK.
// artefaktur provides this software "as is" without express or implied warranty.
// Any AcdkObjectmmercial use of this software requires a license.
//
// $Header: /cvsroot/acdk/acdk/acdkx_com/src/acdkx/com/AcdkObject.cpp,v 1.25 2005/04/18 20:40:37 kommer Exp $
#include "AcdkObject.h"
#include <acdk/lang/Throwable.h>
#include <acdk/io/MemWriter.h>
#include <acdk/io/PrintWriter.h>
#include <acdk/lang/dmi/AcdkDmiClient.h>
#include "ComDmiClient.h"
namespace acdkx {
namespace com {
using namespace acdk::lang::dmi;
#if defined(__BORLANDC__)
using namespace ::acdk::lang::dmi;
#endif
/FONT>
HRESULT STDMETHODCALLTYPE
AcdkObject::QueryInterface(REFIID riid,void** ppvObject)
{
if (CLSID_acdk_lang_Object == riid)
{
addRef();
*ppvObject = (::IAcdkObject*)this;
return S_OK;
}
if (IID_IDispatch == riid)
{
addRef();
*ppvObject = (::IDispatch*)this;
return S_OK;
}
if (IID_IAcdkObject == riid || CLSID_AcdkObject == riid)
{
addRef();
*ppvObject = (::IDispatch*)this;
return S_OK;
}
return AbstractCoInterface::QueryInterface(riid, ppvObject);
}
//virtual
HRESULT STDMETHODCALLTYPE
AcdkObject::InterfaceSupportsErrorInfo(REFIID riid)
{
if (IID_IAcdkObject == riid || CLSID_AcdkObject == riid)
return S_OK;
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE
AcdkObject::GetTypeInfoCount( UINT __RPC_FAR *pctinfo)
{
*pctinfo = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE
AcdkObject::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
{
if (iTInfo != 0)
return DISP_E_BADINDEX;
return ERROR_CALL_NOT_IMPLEMENTED;
}
HRESULT STDMETHODCALLTYPE
AcdkObject::GetIDsOfNames(REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames,
LCID lcid, DISPID __RPC_FAR *rgDispId)
{
HRESULT hr = S_OK;
if (cNames < 1)
return DISP_E_BADINDEX;
if (cNames > 1)
return ERROR_CALL_NOT_IMPLEMENTED;
int _clength;
RString name = OLE2S(rgszNames[0]);
if (name->equals("New") == true)
{
rgDispId[0] = 1;
return S_OK;
}
if (name->equals("invoke") == true || name->equals("Invoke") == true)
{
rgDispId[0] = 2;
return S_OK;
}
if (name->equals("peek") == true || name->equals("Peek") == true)
{
rgDispId[0] = 3;
return S_OK;
}
if (name->equals("poke") == true || name->equals("Poke") == true)
{
rgDispId[0] = 4;
return S_OK;
}
if (name->equals("invoke_static") == true)
{
rgDispId[0] = 5;
return S_OK;
}
if (name->equals("peek_static") == true)
{
rgDispId[0] = 6;
return S_OK;
}
if (name->equals("poke_static") == true)
{
rgDispId[0] = 7;
return S_OK;
}
if (_obj == Nil)
return DISP_E_UNKNOWNNAME;
const ::acdk::lang::dmi::ClazzInfo* ci = _obj->getClazzInfo();
const ::acdk::lang::dmi::ClazzMethodInfo* cmi = lookupMethod(ci, name, MiPublic);
if (cmi != 0)
{
rgDispId[0] = (DISPID)cmi;
return S_OK;
}
int flags = MiPublic;
if (_obj != Nil)
{
ci = _obj->getClazzInfo();
const ClazzFieldInfo* cfi = acdk::lang::dmi::ClazzInfo::findField(ci, name, flags);
if (cfi != 0)
{
rgDispId[0] = (DISPID)cfi;
return S_OK;
}
}
return DISP_E_UNKNOWNNAME;
}
HRESULT
AcdkObject::_invoke(IN(RString) funcname, VARIANT *params, int argcount, VARIANT* result)
{
ScriptVarArray args(argcount);
variants2ScriptVarArray(params, argcount, args, unwrapAcdkObject());
ScriptVar erg;
int flags = MiPublic;
if (_obj == Nil)
flags |= MiStatic;
const ::acdk::lang::dmi::ClazzMethodInfo* cmi =
_obj->standardDispatch(funcname, erg, args, ComDmiClient::getDmiClient(), Nil, flags);
if (cmi == 0)
return DISP_E_BADPARAMCOUNT;
if (result != 0 /*&& result->vt != VT_EMPTY VBScript always set to VT_EMPTY */)
scriptVar2Variant(erg, *result);
variants2ScriptVarArrayOut(params, argcount, args, unwrapAcdkObject());
return S_OK;
}
HRESULT STDMETHODCALLTYPE
AcdkObject::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult,
EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr)
{
try {
switch (wFlags)
{
case DISPATCH_METHOD:
case 0x3: // called from Basic
{
if (dispIdMember == 0) {
return DISP_E_UNKNOWNNAME; //???
} else if (dispIdMember == 1) {// New
if (pDispParams->cArgs < 1)
return DISP_E_BADPARAMCOUNT;
if (pDispParams->rgvarg[pDispParams->cArgs - 1].vt != VT_BSTR)
return DISP_E_BADVARTYPE;
int _clength;
RString classname = OLE2S(pDispParams->rgvarg[pDispParams->cArgs - 1].bstrVal);
pVarResult->vt = VT_DISPATCH;
return new_object(classname, pDispParams->rgvarg, pDispParams->cArgs - 1, &pVarResult->pdispVal);
} else if (dispIdMember == 2) { // invoke
if (pDispParams->cArgs < 1)
return DISP_E_BADPARAMCOUNT;
int _clength;
return _invoke( OLE2CS(pDispParams->rgvarg[pDispParams->cArgs - 1].bstrVal), pDispParams->rgvarg
, pDispParams->cArgs - 1, pVarResult);
} else if (dispIdMember == 3) { // peek
if (pDispParams->cArgs != 1)
return DISP_E_BADPARAMCOUNT;
return peek(pDispParams->rgvarg[0].bstrVal, pVarResult);
} else if (dispIdMember == 4) { // poke
if (pDispParams->cArgs != 2)
return DISP_E_BADPARAMCOUNT;
return poke(pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0]);
} else if (dispIdMember == 5) { // invoke_static
if (pDispParams->cArgs < 2)
return DISP_E_BADPARAMCOUNT;
return invoke_static( pDispParams->rgvarg[pDispParams->cArgs - 1].bstrVal
, pDispParams->rgvarg[pDispParams->cArgs - 2].bstrVal
, pDispParams->rgvarg, pDispParams->cArgs - 2, pVarResult);
} else if (dispIdMember == 6) { // peek_static
if (pDispParams->cArgs != 2)
return DISP_E_BADPARAMCOUNT;
return peek_static(pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].bstrVal, pVarResult);
} else if (dispIdMember == 7) { // poke_static
if (pDispParams->cArgs != 3)
return DISP_E_BADPARAMCOUNT;
return poke_static(pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0]);
} else { // generic invokation
::acdk::lang::dmi::MetaInfo* mi = (::acdk::lang::dmi::MetaInfo*)dispIdMember;
if (mi->flags & MiFieldInfo) {
::acdk::lang::dmi::ClazzFieldInfo* cfi = (::acdk::lang::dmi::ClazzFieldInfo*)mi;
if (pDispParams->cArgs == 0) { // peek
scriptVar2Variant(_obj->peek(cfi->name), *pVarResult);
return S_OK;
} else if (pDispParams->cArgs == 1) { // poke
_obj->poke(cfi->name, variant2ScriptVar(pDispParams->rgvarg[0], unwrapAcdkObject()));
return S_OK;
} else {
return DISP_E_BADPARAMCOUNT;
}
} else if (mi->flags & MiMethodInfo) {
ClazzMethodInfo* cmi = (ClazzMethodInfo*)mi;
// ### handle namedArgs
return _invoke(cmi->name, pDispParams->rgvarg, pDispParams->cArgs, pVarResult);
} else {
return DISP_E_BADINDEX;
}
}
}
case DISPATCH_PROPERTYGET:
{
::acdk::lang::dmi::ClazzFieldInfo* cfi = (::acdk::lang::dmi::ClazzFieldInfo*)dispIdMember;
if ((cfi->flags & MiFieldInfo) == 0)
return DISP_E_BADINDEX;
if (pDispParams->cArgs != 0)
return DISP_E_BADPARAMCOUNT;
scriptVar2Variant(_obj->peek(cfi->name), *pVarResult);
return S_OK;
}
case DISPATCH_PROPERTYPUT:
{
::acdk::lang::dmi::ClazzFieldInfo* cfi = (::acdk::lang::dmi::ClazzFieldInfo*)dispIdMember;
if (cfi == 0)
{
/* in case VB:
"var = othervar"
*/
ScriptVar sv = variant2ScriptVar(pDispParams->rgvarg[0], unwrapAcdkObject());
if (sv.isObjectType() == false)
return DISP_E_BADINDEX;
_obj = sv.getObjectVar();
return S_OK;
}
if ((cfi->flags & MiFieldInfo) == 0)
return DISP_E_BADINDEX;
if (pDispParams->cArgs != 1)
return DISP_E_BADPARAMCOUNT;
_obj->poke(cfi->name, variant2ScriptVar(pDispParams->rgvarg[0], unwrapAcdkObject()));
return S_OK;
}
case DISPATCH_PROPERTYPUTREF:
{
//int* x = 0;
//*x = 0;
return ERROR_CALL_NOT_IMPLEMENTED;
}
default:
return DISP_E_BADINDEX;
}
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
namespace {
template <class T>
struct SafeArrayLock
{
SAFEARRAY& _array;
SafeArrayLock(SAFEARRAY& arr, T* data)
: _array(arr)
{
SafeArrayAccessData(&arr, (void HUGEP* FAR*)data);
}
~SafeArrayLock()
{
SafeArrayUnaccessData(&_array);
}
};
} // anon namespace
HRESULT STDMETHODCALLTYPE
AcdkObject::New(BSTR classname, SAFEARRAY __RPC_FAR * args, IDispatch __RPC_FAR *__RPC_FAR *retvalue)
{
try {
int _clength;
RString clsname = OLE2S(classname);
VARIANT* variants = 0;
SafeArrayLock<VARIANT> sa(*args, variants);
return new_object(clsname, variants, args->cbElements, retvalue);
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::invoke(BSTR methodname, SAFEARRAY __RPC_FAR * args, VARIANT __RPC_FAR *retvalue)
{
try {
int _clength;
VARIANT* variants = 0;
SafeArrayLock<VARIANT> sa(*args, variants);
return _invoke(OLE2CS(methodname), variants, args->cbElements, retvalue);
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::peek(BSTR membername, VARIANT __RPC_FAR *retvalue)
{
try {
int _clength = 0;
RString member = OLE2S(membername);
ScriptVar erg = _obj->peek(member);
if (retvalue != 0)
scriptVar2Variant(erg, *retvalue);
return S_OK;
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::poke( BSTR membername, VARIANT value)
{
try {
int _clength = 0;
RString member = OLE2S(membername);
ScriptVar val = variant2ScriptVar(value, unwrapAcdkObject());
_obj->poke(member, val);
return S_OK;
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT
AcdkObject::invoke_static( BSTR classname, BSTR methodname, VARIANT* args, int argcount, VARIANT __RPC_FAR *retvalue)
{
try {
int _clength;
RString clzname = OLE2S(classname);
RString method = OLE2S(methodname);
ScriptVarArray sargs(argcount);
variants2ScriptVarArray(args, argcount, sargs, unwrapAcdkObject());
ScriptVar erg = StdDispatch::invokeStaticMethod(clzname, method, sargs, ComDmiClient::getDmiClient(), Nil);
variants2ScriptVarArray(args, argcount, sargs, unwrapAcdkObject());
if (retvalue != 0)
scriptVar2Variant(erg, *retvalue);
return S_OK;
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::invoke_static( BSTR classname, BSTR methodname, SAFEARRAY __RPC_FAR * args, VARIANT __RPC_FAR *retvalue)
{
try {
VARIANT* variants = 0;
SafeArrayLock<VARIANT> sa(*args, variants);
return invoke_static(classname, methodname, variants, args->cbElements, retvalue);
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::peek_static(BSTR classname, BSTR membername, VARIANT __RPC_FAR *retvalue)
{
try {
int _clength;
RString clzname = OLE2S(classname);
RString member = OLE2S(membername);
ScriptVar ret = StdDispatch::peek_static(clzname, member);
if (retvalue != 0)
scriptVar2Variant(ret, *retvalue);
return S_OK;
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
HRESULT STDMETHODCALLTYPE
AcdkObject::poke_static(BSTR classname, BSTR membername, VARIANT value)
{
RString clss;
try {
int _clength;
clss = OLE2S(classname);
clss = clss->narrow();
StdDispatch::poke_static(clss, OLE2S(membername), variant2ScriptVar(value, unwrapAcdkObject()));
return S_OK;
} catch (RThrowable ex) {
return createErrorInfoFromException(ex);
}
}
//static
HRESULT
AcdkObject::new_object(IN(RString) classname, VARIANT* args, int argnum, IDispatch __RPC_FAR *__RPC_FAR *retvalue)
{
ScriptVarArray sargs(argnum);
for (int i = 0; i < argnum; ++i)
{
sargs[argnum - (i + 1)] = variant2ScriptVar(args[i], unwrapAcdkObject());
}
RClass cls = Class::forName(classname);
if (cls == Nil)
{
return DISP_E_TYPEMISMATCH;
}
/*
RString constructorname = classname;
if (constructorname->indexOf('/') != -1)
constructorname = constructorname->substr(constructorname->lastIndexOf('/') + 1);
*/
ScriptVar ret = StdDispatch::New(classname, sargs, ComDmiClient::getDmiClient());
AcdkObject* acobj = new AcdkObject(ret.getObjectVar());
acobj->addRef();
*retvalue = acobj;
return S_OK;
}
//static
HRESULT
AcdkObject::createErrorInfoFromException(IN(RThrowable) ex)
{
ICreateErrorInfo* cei;
CreateErrorInfo(&cei);
RString msg = ex->getMessage()->convert(CCUcs2);
cei->SetDescription((wchar_t*)S2OLE(msg));
cei->SetGUID(IID_IAcdkObject);
acdk::io::MemWriter sw;
acdk::io::PrintWriter out(&sw);
ex->printStackTrace(&out);
RString str = (new String(sw.getBuffer()))->convert(CCUcs2);
cei->SetSource((wchar_t*)S2OLE(str));
IErrorInfo* ei;
cei->QueryInterface(IID_IErrorInfo, (void**)&ei);
SetErrorInfo(0, ei);
cei->Release();
ei->Release();
return E_FAIL;
}
} // namespace com
} // namespace acdkx
|