#include <math.h> /* this hack gets around VC-5.0 brainmelt */
#include <windows.h>
#include <objbase.h>
#include <winnt.h>
#include <oleauto.h>
#include <malloc.h>
#define WIN32_LEAN_AND_MEAN
#if defined(__cplusplus)
extern
"C"
{
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSub.h"
#undef bool /* perl defines bool to char which breaks things */
#undef DEB
#ifdef MYDEBUG
#define DEB(a) a
#else
#define DEB(a)
#endif
#define SUCCESSRETURNED(x) (x == ERROR_SUCCESS)
#define RETURNRESULT if (bSuccess) { XST_mYES(0); }\
else
{ XST_mNO(0); }\
XSRETURN(1)
#define NEW(x,v,n,t) (v = (t*)safemalloc((MEM_SIZE)((n) * sizeof(t))))
#define INTERNAL_ERROR ((HRESULT)-1)
static
long
LastOLEError;
static
const
DWORD
WINOLE_MAGIC = 0x12344321;
static
const
int
OLE_BUF_SIZ = 1024;
static
const
LCID
lcidDefault = (0x02 << 10)
;
static
char
PERL_OLE_ID[] =
"___Perl___OLEObject___"
;
static
const
int
PERL_OLE_IDLEN =
sizeof
(PERL_OLE_ID)-1;
static
char
IV_TYPE[] =
"Type"
;
static
const
int
IV_TYPELEN =
sizeof
(IV_TYPE)-1;
static
char
IV_VAL[] =
"Value"
;
static
const
int
IV_VALLEN =
sizeof
(IV_VAL)-1;
typedef
struct
_tagWINOLEOBJECT *LPWINOLEOBJECT;
typedef
struct
_tagWINOLEOBJECT
{
long
Win32OLEMagic;
LPWINOLEOBJECT pNext;
LPWINOLEOBJECT pPrevious;
IDispatch* pDispatch;
IEnumVARIANT *pEnum;
HV* hashTable;
} WINOLEOBJECT;
static
LPWINOLEOBJECT g_lpObj = NULL;
#ifdef _DEBUG
inline
void
EXCEPTIONINFOCLEAR(EXCEPINFO &excepinfo)
{
memset
(&excepinfo, 0,
sizeof
(EXCEPINFO));
}
inline
void
EXCEPTIONINFO(
HRESULT
lastError, EXCEPINFO &excepinfo)
{
if
(FAILED(lastError)) {
OutputDebugString(
"Exception Source: "
);
ODSOLE(excepinfo.bstrSource);
OutputDebugString(
" Description: "
);
ODSOLE(excepinfo.bstrDescription);
}
}
inline
void
ODS(
LPSTR
x)
{
OutputDebugString(x);
OutputDebugString(
"\n"
);
}
#if defined(UNICODE)
# define ODSOLE(x) ODS(x)
#else
inline
void
ODSOLE(
LPCWSTR
x)
{
char
bufA[256];
if
(x != NULL)
WideCharToMultiByte(CP_ACP, NULL, x, -1, bufA, 256, NULL, NULL);
else
strcpy
(bufA,
"<null>"
);
ODS(bufA);
}
#endif /* UNICODE */
#else /* _DEBUG */
# define EXCEPTIONINFOCLEAR(x)
# define EXCEPTIONINFO(x, y)
# define ODS(x)
# define ODSOLE(x)
#endif /* _DEBUG */
void
ReleaseObjects(LPWINOLEOBJECT lpObj)
{
DEB(
fprintf
(stderr,
"ReleaseObjects |%lx|"
, lpObj));
if
(lpObj->pDispatch != NULL) {
lpObj->pDispatch->Release();
lpObj->pDispatch = NULL;
DEB(
fprintf
(stderr,
" pDispatch"
));
}
if
(lpObj->hashTable != NULL) {
DEB(
fprintf
(stderr,
" hashTable(%d)"
, SvREFCNT(lpObj->hashTable)));
SvREFCNT_dec(lpObj->hashTable);
lpObj->hashTable = NULL;
}
DEB(
fprintf
(stderr,
"\n"
));
}
LPWINOLEOBJECT
NewDispatch(IDispatch* pDisp,
BOOL
bCreated)
{
LPWINOLEOBJECT lpObj;
NEW(2101, lpObj, 1, WINOLEOBJECT);
lpObj->Win32OLEMagic = WINOLE_MAGIC;
lpObj->pPrevious = NULL;
lpObj->pEnum = NULL;
lpObj->pDispatch = pDisp;
lpObj->hashTable = newHV();
lpObj->pNext = g_lpObj;
if
(g_lpObj)
g_lpObj->pPrevious = lpObj;
g_lpObj = lpObj;
DEB(
fprintf
(stderr,
"NewDispatch = |%lx|\n"
, lpObj));
if
(!bCreated)
pDisp->AddRef();
return
lpObj;
}
SV *
sv_setrv(SV *dest, SV *obj,
char
*classname)
{
sv_upgrade(dest, SVt_RV);
SvRV(dest) = obj;
SvTEMP_off(obj);
SvROK_on(dest);
if
(classname)
(
void
)sv_bless(dest, gv_stashpv(classname, TRUE));
return
dest;
}
IV
CreatePerlObject(SV *newref, IDispatch *pDisp,
BOOL
bCreated)
{
if
(pDisp != NULL) {
HV *hvouter = newHV();
HV *hvinner = newHV();
SV *inner = newSVpv(
""
,0);
hv_store(hvinner, PERL_OLE_ID, PERL_OLE_IDLEN,
newSViv((
long
)NewDispatch(pDisp, bCreated)), 0);
sv_setrv(inner, (SV*)hvinner,
"Win32::OLE::Tie"
);
sv_magic((SV*)hvouter, inner,
'P'
, Nullch, 0);
SvREFCNT_dec(inner);
sv_setrv(newref, (SV*)hvouter,
"Win32::OLE"
);
return
TRUE;
}
return
FALSE;
}
LPWINOLEOBJECT
GetOLEObject(SV *sv)
{
SV **psv;
if
(sv != NULL && SvROK(sv)) {
psv = hv_fetch((HV*)SvRV(sv), PERL_OLE_ID, PERL_OLE_IDLEN, 0);
if
(psv != NULL) {
DEB(
fprintf
(stderr,
"GetOLEObject = |%lx|\n"
, SvIV(*psv)));
return
(LPWINOLEOBJECT)SvIV(*psv);
}
}
return
(LPWINOLEOBJECT)NULL;
}
inline
BOOL
IsOleStruct(LPWINOLEOBJECT lpObj)
{
return
(lpObj != NULL && lpObj->Win32OLEMagic == WINOLE_MAGIC);
}
inline
BOOL
ValidDispatch(LPWINOLEOBJECT lpObj)
{
return
(IsOleStruct(lpObj) && lpObj->pDispatch != NULL);
}
BSTR
AllocOLEString(
char
* lpStr,
int
length)
{
int
count = (length+1)*2;
OLECHAR* pOLEChar = (OLECHAR*)alloca(count);
MultiByteToWideChar(CP_ACP, 0, lpStr, -1, pOLEChar, count);
return
SysAllocString(pOLEChar);
}
BOOL
GetHashedDispID(LPWINOLEOBJECT lpObj,
char
*buffer, unsigned
int
length, DISPID &dispID)
{
if
(length == 0 || *buffer ==
'\0'
) {
dispID = DISPID_VALUE;
return
TRUE;
}
if
(!hv_exists(lpObj->hashTable, buffer, length)) {
DISPID id;
OLECHAR bBuffer[OLE_BUF_SIZ], *pbBuffer;
SV* sv;
pbBuffer = bBuffer;
MultiByteToWideChar(CP_ACP, NULL, buffer, -1, bBuffer,
sizeof
(bBuffer));
LastOLEError = lpObj->pDispatch->GetIDsOfNames(IID_NULL, &pbBuffer, 1, lcidDefault, &id);
if
(SUCCEEDED(LastOLEError)) {
sv = newSViv(id);
hv_store(lpObj->hashTable, buffer, length, sv, 0);
dispID = id;
return
TRUE;
}
}
else
{
SV** ppsv;
ppsv = hv_fetch(lpObj->hashTable, buffer, length, 0);
if
(ppsv != NULL) {
dispID = (DISPID)SvIV(*ppsv);
return
TRUE;
}
LastOLEError = INTERNAL_ERROR;
}
return
FALSE;
}
void
CreateSafeBinaryArray(SV* sv, VARIANT *pVariant)
{
unsigned
char
* ptr;
unsigned
int
length;
SAFEARRAYBOUND rgsabound;
unsigned
char
* pDest;
ptr = (unsigned
char
*)SvPV(sv, length);
rgsabound.lLbound = 0;
rgsabound.cElements = length;
pVariant->parray = SafeArrayCreate(VT_UI1, 1, &rgsabound);
if
(pVariant->parray != NULL) {
pVariant->vt = VT_UI1 | VT_ARRAY;
HRESULT
hResult = SafeArrayAccessData(pVariant->parray, (
void
**)&pDest);
if
(SUCCEEDED(hResult)) {
memcpy
(pDest, ptr, length);
SafeArrayUnaccessData(pVariant->parray);
}
}
}
void
CreateSafeArray(AV* av, VARIANT *pVariant)
{
SV **psv;
char
*ptr;
unsigned
int
length;
SAFEARRAYBOUND rgsabound;
long
arrayIndex;
VARIANT variant;
rgsabound.lLbound = 0;
rgsabound.cElements = av_len(av)+1;
pVariant->parray = SafeArrayCreate(VT_VARIANT, 1, &rgsabound);
if
(pVariant->parray != NULL) {
pVariant->vt = VT_VARIANT | VT_ARRAY;
VariantInit(&variant);
variant.vt = VT_BSTR;
for
(arrayIndex = 0; arrayIndex < rgsabound.cElements; ++arrayIndex) {
psv = av_fetch(av, arrayIndex, 0);
if
(psv != NULL) {
ptr = SvPV(*psv, length);
variant.bstrVal = AllocOLEString(ptr, length);
if
(variant.bstrVal != NULL)
SafeArrayPutElement(pVariant->parray, &arrayIndex, &variant);
}
}
}
}
void
DestroySafeArray(VARIANT *pVariant)
{
long
arrayIndex, upperBound;
VARIANT variant;
HRESULT
hResult;
hResult = SafeArrayGetUBound(pVariant->parray, 1, &upperBound);
if
(SUCCEEDED(hResult)) {
for
(arrayIndex = 0; arrayIndex <= upperBound; ++arrayIndex) {
hResult = SafeArrayGetElement(pVariant->parray, &arrayIndex, &variant);
if
(SUCCEEDED(hResult)) {
if
(variant.vt == VT_BSTR) {
SysFreeString(variant.bstrVal);
variant.bstrVal = NULL;
SafeArrayPutElement(pVariant->parray, &arrayIndex, &variant);
}
}
}
}
SafeArrayDestroy(pVariant->parray);
pVariant->parray = NULL;
}
void
CreateVariantFromInternalVariant(SV* sv, VARIANT *pVariant)
{
char
*ptr;
unsigned
int
length;
int
nType;
SV **psv;
HV* hv = (HV*)SvRV(sv);
psv = hv_fetch(hv, IV_TYPE, IV_TYPELEN, 0);
if
(psv != NULL) {
nType = SvIV(*psv);
psv = hv_fetch(hv, IV_VAL, IV_VALLEN, 0);
if
(psv != NULL) {
switch
(nType) {
case
VT_UI1:
switch
(SvTYPE(*psv)) {
case
SVt_PVIV:
case
SVt_PV:
CreateSafeBinaryArray(*psv, pVariant);
break
;
default
:
V_VT(pVariant) = VT_UI1;
V_UI1(pVariant) = SvIV(*psv);
break
;
}
break
;
case
VT_BOOL:
V_VT(pVariant) = VT_BOOL;
V_BOOL(pVariant) = SvIV(*psv);
break
;
case
VT_I2:
V_VT(pVariant) = VT_I2;
V_I2(pVariant) = SvIV(*psv);
break
;
case
VT_I4:
V_VT(pVariant) = VT_I4;
V_I4(pVariant) = SvIV(*psv);
break
;
case
VT_R4:
V_VT(pVariant) = VT_R4;
V_R4(pVariant) = SvNV(*psv);
break
;
case
VT_R8:
V_VT(pVariant) = VT_R8;
V_R8(pVariant) = SvNV(*psv);
break
;
case
VT_BSTR:
V_VT(pVariant) = VT_BSTR;
ptr = SvPV(*psv, length);
V_BSTR(pVariant) = AllocOLEString(ptr, length);
break
;
case
VT_DATE:
case
VT_CY:
V_VT(pVariant) = VT_BSTR;
ptr = SvPV(*psv, length);
V_BSTR(pVariant) = AllocOLEString(ptr, length);
VariantChangeType(pVariant, pVariant, 0, nType);
break
;
}
}
}
}
void
CreateVariantFromSV(SV* sv, VARIANT *pVariant)
{
char
*ptr;
unsigned
int
length;
int
type;
VariantInit(pVariant);
if
(SvROK(sv)) {
if
(sv_isa(sv,
"Win32::OLE"
)) {
LPWINOLEOBJECT lpObj;
lpObj = GetOLEObject(sv);
if
(ValidDispatch(lpObj) && lpObj->hashTable != NULL) {
V_VT(pVariant) = VT_DISPATCH;
V_DISPATCH(pVariant) = lpObj->pDispatch;
return
;
}
}
else
if
(sv_isa(sv,
"Win32::OLE::Variant"
)) {
CreateVariantFromInternalVariant(sv, pVariant);
return
;
}
sv = SvRV(sv);
}
type = SvTYPE(sv);
if
(type == SVt_PVMG) {
if
(SvPOKp(sv))
type = SVt_PV;
else
if
(SvNOKp(sv))
type = SVt_NV;
else
if
(SvIOKp(sv))
type = SVt_IV;
}
switch
(type)
{
case
SVt_PVAV:
CreateSafeArray((AV*)sv, pVariant);
break
;
case
SVt_PVIV:
case
SVt_PV:
pVariant->vt = VT_BSTR;
ptr = SvPV(sv, length);
pVariant->bstrVal = AllocOLEString(ptr, length);
break
;
case
SVt_NV:
pVariant->vt = VT_R8;
pVariant->dblVal = SvNV(sv);
break
;
default
:
pVariant->vt = VT_I4;
pVariant->lVal = SvIV(sv);
break
;
}
}
#define SETiVRETURN(x,f)\
if
(x->vt&VT_BYREF) {\
sv_setiv(sv, (
long
)*x->p##f);\
}
else
{\
sv_setiv(sv, (
long
)x->f);\
}
#define SETnVRETURN(x,f)\
if
(x->vt&VT_BYREF) {\
sv_setnv(sv, (
double
)*x->p##f);\
}
else
{\
sv_setnv(sv, (
double
)x->f);\
}
void
SVFromVariant(VARIANT *pVariant, SV* sv)
{
switch
(pVariant->vt&~VT_BYREF)
{
case
VT_EMPTY:
case
VT_NULL:
sv_setsv(sv, &sv_undef);
break
;
case
VT_UI1:
SETiVRETURN(pVariant,bVal)
break
;
case
VT_I2:
SETiVRETURN(pVariant,iVal)
break
;
case
VT_I4:
SETiVRETURN(pVariant,lVal)
break
;
case
VT_R4:
SETnVRETURN(pVariant,fltVal)
break
;
case
VT_R8:
SETnVRETURN(pVariant,dblVal)
break
;
case
VT_BSTR:
ConvertString:
{
int
length;
char
*pStr;
if
(pVariant->vt&VT_BYREF)
length = SysStringLen(*pVariant->pbstrVal)+2;
else
length = SysStringLen(pVariant->bstrVal)+2;
NEW(1110, pStr, length,
char
);
if
(pVariant->vt&VT_BYREF)
WideCharToMultiByte(CP_ACP, NULL, *pVariant->pbstrVal,
-1, pStr, length, NULL, NULL);
else
WideCharToMultiByte(CP_ACP, NULL, pVariant->bstrVal,
-1, pStr, length, NULL, NULL);
sv_setpv(sv, pStr);
Safefree(pStr);
}
break
;
case
VT_ERROR:
SETiVRETURN(pVariant,scode)
break
;
case
VT_BOOL:
if
(pVariant->vt&VT_BYREF)
sv_setiv(sv, (
long
)V_BOOLREF(pVariant));
else
sv_setiv(sv, (
long
)V_BOOL(pVariant));
break
;
case
VT_DISPATCH:
{
IDispatch *pDisp;
if
(pVariant->vt&VT_BYREF)
pDisp = (IDispatch*)*pVariant->ppunkVal;
else
pDisp = (IDispatch*)pVariant->punkVal;
CreatePerlObject(sv, pDisp,FALSE);
}
break
;
case
VT_UNKNOWN:
{
IUnknown *punk;
IDispatch *pDisp;
if
(pVariant->vt&VT_BYREF)
punk = (IUnknown*)*pVariant->ppunkVal;
else
punk = (IUnknown*)pVariant->punkVal;
if
(SUCCEEDED(punk->QueryInterface(IID_IDispatch,
(
void
**)&pDisp))) {
CreatePerlObject(sv, pDisp,FALSE);
}
else
sv_setsv(sv, &sv_undef);
punk->Release();
}
break
;
case
VT_DATE:
case
VT_CY:
case
VT_VARIANT:
default
:
{
HRESULT
hResult = VariantChangeType(pVariant, pVariant,
0, VT_BSTR);
if
(SUCCEEDED(hResult))
goto
ConvertString;
}
sv_setsv(sv, &sv_undef);
break
;
}
}
void
SetSVFromVariant(VARIANT *pVariant, SV* sv)
{
if
(pVariant->vt&VT_ARRAY) {
SV *nsv;
AV *av;
VARIANT variant;
int
dim, index;
long
*pArrayIndex, *pLowerBound, *pUpperBound;
HRESULT
hResult;
dim = SafeArrayGetDim(pVariant->parray);
NEW(4444, pArrayIndex, dim,
long
);
NEW(4444, pLowerBound, dim,
long
);
NEW(4444, pUpperBound, dim,
long
);
for
(index = 1; index <= dim; ++index) {
hResult = SafeArrayGetLBound(pVariant->parray, index,
&pLowerBound[index-1]);
if
(FAILED(hResult))
goto
ErrorExit;
}
for
(index = 1; index <= dim; ++index) {
hResult = SafeArrayGetUBound(pVariant->parray, index,
&pUpperBound[index-1]);
if
(FAILED(hResult))
goto
ErrorExit;
}
av = newAV();
if
(dim < 3)
{
memcpy
(pArrayIndex, pLowerBound, dim*
sizeof
(
long
));
for
(index = dim-1;
pArrayIndex[index] <= pUpperBound[index];
++pArrayIndex[index])
{
hResult = SafeArrayGetElement(pVariant->parray, pArrayIndex,
&variant);
if
(SUCCEEDED(hResult)) {
nsv = newSVpv(
""
,0);
SetSVFromVariant(&variant, nsv);
av_push(av, nsv);
}
}
}
sv_setrv(sv, (SV*)av, Nullch);
ErrorExit:
Safefree(pArrayIndex);
Safefree(pLowerBound);
Safefree(pUpperBound);
}
else
SVFromVariant(pVariant, sv);
}
SV *
Win32OLEPropertyGet(SV *object, SV *propname)
{
char
*buffer;
unsigned
int
length, argErr;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPPARAMS dispParams;
VARIANT result;
DISPID dispID;
BOOL
bSuccess = FALSE;
SV* sv = NULL;
lpObj = (LPWINOLEOBJECT)SvIV(object);
if
(ValidDispatch(lpObj)) {
VariantInit(&result);
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cNamedArgs = 0;
dispParams.cArgs = 0;
buffer = SvPV(propname, length);
if
(GetHashedDispID(lpObj, buffer, length, dispID)) {
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL,
lcidDefault, DISPATCH_METHOD | DISPATCH_PROPERTYGET,
&dispParams, &result, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
bSuccess = SUCCEEDED(LastOLEError);
}
if
(bSuccess) {
sv = newSVpv(
""
,0);
SetSVFromVariant(&result, sv);
VariantClear(&result);
}
}
return
sv;
}
SV *
Win32OLEPropertySet(SV *object, SV *propname, SV *val)
{
unsigned
int
length, argErr;
char
*buffer;
int
index;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPID dispID, dispIDParam;
DISPPARAMS dispParams;
VARIANT propertyValue;
BOOL
bSuccess = FALSE;
lpObj = (LPWINOLEOBJECT)SvIV(object);
if
(ValidDispatch(lpObj)) {
dispIDParam = DISPID_PROPERTYPUT;
dispParams.rgvarg = &propertyValue;
dispParams.rgdispidNamedArgs = &dispIDParam;
dispParams.cNamedArgs = 1;
dispParams.cArgs = 1;
CreateVariantFromSV(val, &propertyValue);
buffer = SvPV(propname, length);
if
(GetHashedDispID(lpObj, buffer, length, dispID)) {
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL,
lcidDefault, DISPATCH_PROPERTYPUT,
&dispParams, NULL, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
bSuccess = SUCCEEDED(LastOLEError);
}
if
(propertyValue.vt == VT_BSTR)
SysFreeString(propertyValue.bstrVal);
else
if
(propertyValue.vt == (VT_VARIANT | VT_ARRAY))
DestroySafeArray(&propertyValue);
}
return
(bSuccess ? val : NULL);
}
BOOL
APIENTRY
DllMain(
HANDLE
hModule,
DWORD
fdwReason,
LPVOID
lpvReserved)
{
switch
(fdwReason) {
case
DLL_PROCESS_ATTACH:
OleInitialize(NULL);
break
;
case
DLL_PROCESS_DETACH:
while
(g_lpObj != NULL) {
LPWINOLEOBJECT i = g_lpObj;
DEB(
fprintf
(stderr,
"Cleaning out escaped object |%lx|\n"
, i));
g_lpObj = i->pNext;
ReleaseObjects(i);
}
OleUninitialize();
break
;
default
:
break
;
}
return
TRUE;
}
#if defined(__cplusplus)
}
#endif
MODULE = Win32::OLE PACKAGE = Win32::OLE
PROTOTYPES: DISABLE
IV
LastError()
CODE:
RETVAL = LastOLEError;
OUTPUT:
RETVAL
IV
CreateObject(clas,obj)
SV *clas
SV *obj
PPCODE:
{
CLSID CLSIDObj;
OLECHAR bBuffer[OLE_BUF_SIZ];
unsigned
int
length;
char
*buffer;
HKEY
handle;
IDispatch *pDisp;
BOOL
bSuccess = FALSE;
buffer = SvPV(clas, length);
MultiByteToWideChar(CP_ACP, NULL, buffer, -1, bBuffer,
sizeof
(bBuffer));
LastOLEError = CLSIDFromProgID(bBuffer, &CLSIDObj);
if
(SUCCEEDED(LastOLEError)) {
LastOLEError = CoCreateInstance(CLSIDObj, NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch, (
void
**)&pDisp);
if
(FAILED(LastOLEError))
LastOLEError = CoCreateInstance(CLSIDObj, NULL, CLSCTX_ALL,
IID_IDispatch, (
void
**)&pDisp);
if
(SUCCEEDED(LastOLEError)) {
if
(CreatePerlObject(obj, pDisp, TRUE)) {
DEB(
fprintf
(stderr,
"CreateObject = |%lx| |%lx|\n"
,
(
long
) obj, (
long
)pDisp));
bSuccess = TRUE;
}
}
}
RETURNRESULT;
}
IV
Dispatch(object,funcName,funcReturn,...)
SV *object
SV *funcName
SV *funcReturn
PPCODE:
{
char
*buffer;
char
*ptr;
unsigned
int
length, argErr;
int
index, arrayIndex;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPID dispID;
VARIANT result;
DISPPARAMS dispParams;
BOOL
bSuccess = FALSE;
lpObj = GetOLEObject(object);
if
(ValidDispatch(lpObj) && lpObj->hashTable != NULL) {
VariantInit(&result);
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cNamedArgs = 0;
dispParams.cArgs = items - 3;
if
(dispParams.cArgs > 0) {
NEW(2101, dispParams.rgvarg, dispParams.cArgs, VARIANTARG);
for
(index = 0; index < dispParams.cArgs; ++index)
CreateVariantFromSV(ST(items - 1 - index),
&dispParams.rgvarg[index]);
}
buffer = SvPV(funcName, length);
DEB(
fprintf
(stderr,
"Dispatch \"%s\"\n"
, buffer));
if
(GetHashedDispID(lpObj, buffer, length, dispID)) {
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL,
lcidDefault,
DISPATCH_METHOD | DISPATCH_PROPERTYGET,
&dispParams, &result, &excepinfo, &argErr);
if
(FAILED(LastOLEError)) {
EXCEPTIONINFO(LastOLEError, excepinfo);
if
(LastOLEError == DISP_E_EXCEPTION && dispID > 0x8000) {
EXCEPTIONINFOCLEAR(excepinfo);
VariantClear(&result);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL,
lcidDefault,
DISPATCH_METHOD | DISPATCH_PROPERTYGET,
&dispParams, NULL, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
if
(SUCCEEDED(LastOLEError))
bSuccess = TRUE;
}
}
else
bSuccess = TRUE;
}
if
(bSuccess) {
SetSVFromVariant(&result, funcReturn);
}
VariantClear(&result);
if
(dispParams.cArgs != 0) {
for
(index = 0; index < dispParams.cArgs; ++index) {
if
(dispParams.rgvarg[index].vt == VT_BSTR)
SysFreeString(dispParams.rgvarg[index].bstrVal);
else
if
(dispParams.rgvarg[index].vt == (VT_VARIANT | VT_ARRAY))
DestroySafeArray(&dispParams.rgvarg[index]);
}
Safefree(dispParams.rgvarg);
}
}
RETURNRESULT;
}
IV
GetProperty(object,varName,varReturn,...)
SV *object
SV *varName
SV *varReturn
PPCODE:
{
char
*buffer;
unsigned
int
length, argErr;
int
index;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPPARAMS dispParams;
VARIANT result;
DISPID dispID;
BOOL
bSuccess = FALSE;
lpObj = GetOLEObject(object);
if
(ValidDispatch(lpObj)) {
VariantInit(&result);
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cNamedArgs = 0;
dispParams.cArgs = items - 3;
if
(dispParams.cArgs > 0) {
NEW(2101, dispParams.rgvarg, dispParams.cArgs, VARIANTARG);
for
(index = 0; index < dispParams.cArgs; ++index) {
VariantInit(&dispParams.rgvarg[index]);
dispParams.rgvarg[index].vt = VT_BSTR;
buffer = SvPV(ST(items - 1 - index), length);
dispParams.rgvarg[index].bstrVal = AllocOLEString(buffer, length);
}
}
buffer = SvPV(varName, length);
if
(GetHashedDispID(lpObj, buffer, length, dispID)) {
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL, lcidDefault, DISPATCH_METHOD | DISPATCH_PROPERTYGET,
&dispParams, &result, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
bSuccess = SUCCEEDED(LastOLEError);
}
if
(bSuccess) {
SetSVFromVariant(&result, varReturn);
VariantClear(&result);
}
if
(dispParams.cArgs != 0) {
for
(index = 0; index < dispParams.cArgs; ++index) {
if
(dispParams.rgvarg[index].vt == VT_BSTR)
SysFreeString(dispParams.rgvarg[index].bstrVal);
}
Safefree(dispParams.rgvarg);
}
}
RETURNRESULT;
}
IV
SetProperty(object,varName,varValue,...)
SV *object
SV *varName
SV *varValue
PPCODE:
{
unsigned
int
length, argErr;
char
*buffer;
int
index;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPID dispID;
DISPID dispidNamed;
DISPPARAMS dispParams;
BOOL
bSuccess = FALSE;
lpObj = GetOLEObject(object);
if
(ValidDispatch(lpObj)) {
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cNamedArgs = 0;
dispParams.cArgs = items - 2;
if
(dispParams.cArgs > 0) {
NEW(2101, dispParams.rgvarg, dispParams.cArgs, VARIANTARG);
dispParams.rgvarg[0].vt = VT_BSTR;
buffer = SvPV(ST(2), length);
dispParams.rgvarg[0].bstrVal = AllocOLEString(buffer, length);
if
(dispParams.cArgs > 1) {
dispidNamed = DISPID_PROPERTYPUT;
dispParams.rgdispidNamedArgs = &dispidNamed;
dispParams.cNamedArgs = 1;
for
(index = 1; index < dispParams.cArgs; ++index)
CreateVariantFromSV(ST(items - index),
&dispParams.rgvarg[index]);
}
}
buffer = SvPV(varName, length);
if
(GetHashedDispID(lpObj, buffer, length, dispID)) {
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(dispID, IID_NULL,
lcidDefault, DISPATCH_PROPERTYPUT,
&dispParams, NULL, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
bSuccess = SUCCEEDED(LastOLEError);
}
if
(dispParams.cArgs > 0) {
if
(dispParams.rgvarg[0].vt == VT_BSTR)
SysFreeString(dispParams.rgvarg[0].bstrVal);
Safefree(dispParams.rgvarg);
}
}
RETURNRESULT;
}
MODULE = Win32::OLE PACKAGE = Win32::OLE::Tie
void
DESTROY(self)
SV *self
CODE:
{
if
(self && SvROK(self)) {
LPWINOLEOBJECT lpObj = GetOLEObject(self);
if
(IsOleStruct(lpObj)) {
DEB(
fprintf
(stderr,
"Win32::OLE::Tie::DESTROY |%lx| |%lx|\n"
,
(
long
)lpObj, (
long
)lpObj->pDispatch));
ReleaseObjects(lpObj);
if
(lpObj->pPrevious == NULL) {
g_lpObj = lpObj->pNext;
if
(lpObj->pNext != NULL)
lpObj->pNext->pPrevious = NULL;
}
else
if
(lpObj->pNext == NULL)
lpObj->pPrevious->pNext = NULL;
else
{
lpObj->pPrevious->pNext = lpObj->pNext;
lpObj->pNext->pPrevious = lpObj->pPrevious;
}
Safefree(lpObj);
}
}
}
SV *
FETCH(self,key)
SV *self
SV *key
PPCODE:
{
SV **coo;
SV *temp;
ST(0) = &sv_undef;
coo = hv_fetch((HV*)SvRV(self), PERL_OLE_ID, PERL_OLE_IDLEN, 0);
DEB(
fprintf
(stderr,
"Win32::OLE::Tie::FETCH |%s| |%d| |%lx|\n"
,
PERL_OLE_ID, PERL_OLE_IDLEN,(
long
)coo));
if
(coo != NULL) {
if
(
strcmp
(SvPV(key,na), PERL_OLE_ID) == 0) {
ST(0) = *coo;
}
else
{
temp = Win32OLEPropertyGet(*coo, key);
if
(temp && temp != &sv_undef)
ST(0) = sv_2mortal(temp);
}
}
XSRETURN(1);
}
void
STORE(self,key,value)
SV *self
SV *key
SV *value
CODE:
{
SV **coo;
coo = hv_fetch((HV*)SvRV(self), PERL_OLE_ID, PERL_OLE_IDLEN, 0);
DEB(
fprintf
(stderr,
"Win32::OLE::Tie::STORE |%s| |%d| |%lx|\n"
,
PERL_OLE_ID, PERL_OLE_IDLEN,(
long
)coo));
if
(coo != NULL)
Win32OLEPropertySet(*coo, ST(1), ST(2));
}
SV *
FIRSTKEY(self)
SV *self
PPCODE:
{
SV **coo;
unsigned
int
argErr;
LPWINOLEOBJECT lpObj;
EXCEPINFO excepinfo;
DISPPARAMS dispParams;
VARIANT result;
BOOL
bSuccess = FALSE;
ST(0) = &sv_undef;
coo = hv_fetch((HV*)SvRV(self), PERL_OLE_ID, PERL_OLE_IDLEN, 0);
DEB(
fprintf
(stderr,
"Win32::OLE::Tie::FIRSTKEY |%s| |%d| |%lx|\n"
,
PERL_OLE_ID, PERL_OLE_IDLEN,(
long
)coo));
if
(coo != NULL) {
lpObj = (LPWINOLEOBJECT)SvIV(*coo);
if
(ValidDispatch(lpObj)) {
VariantInit(&result);
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cNamedArgs = 0;
dispParams.cArgs = 0;
EXCEPTIONINFOCLEAR(excepinfo);
LastOLEError = lpObj->pDispatch->Invoke(DISPID_NEWENUM, IID_NULL,
lcidDefault,
DISPATCH_METHOD | DISPATCH_PROPERTYGET,
&dispParams, &result, &excepinfo, &argErr);
EXCEPTIONINFO(LastOLEError, excepinfo);
bSuccess = SUCCEEDED(LastOLEError);
if
(bSuccess) {
if
((result.vt&~VT_BYREF) == VT_UNKNOWN) {
IUnknown *punk;
IDispatch *pDisp;
IEnumVARIANT *pEnum;
if
(result.vt&VT_BYREF)
punk = (IUnknown*)*result.ppunkVal;
else
punk = (IUnknown*)result.punkVal;
if
(SUCCEEDED(punk->QueryInterface(IID_IDispatch,
(
void
**)&pDisp))) {
CreatePerlObject((ST(0) = newSVsv(&sv_undef)),
pDisp,FALSE);
}
else
if
(SUCCEEDED(punk->QueryInterface(IID_IEnumVARIANT,
(
void
**)&pEnum))) {
if
(lpObj->pEnum != NULL)
lpObj->pEnum->Release();
lpObj->pEnum = pEnum;
VariantClear(&result);
if
(SUCCEEDED(pEnum->Reset())
&& SUCCEEDED(pEnum->Next(1, &result, NULL)))
SetSVFromVariant(&result, (ST(0) = newSVpv(
""
,0)));
}
punk->Release();
}
else
SetSVFromVariant(&result, (ST(0) = newSVpv(
""
,0)));
VariantClear(&result);
}
}
if
(ST(0) != &sv_undef)
sv_2mortal(ST(0));
}
XSRETURN(1);
}
SV *
NEXTKEY(self,lastKey)
SV *self
SV *lastKey
PPCODE:
{
SV **coo;
LPWINOLEOBJECT lpObj;
VARIANT result;
BOOL
bSuccess = FALSE;
coo = hv_fetch((HV*)SvRV(ST(0)), PERL_OLE_ID, PERL_OLE_IDLEN, 0);
DEB(
fprintf
(stderr,
"Win32::OLE::Tie::NEXTKEY |%s| |%d| |%lx|\n"
,
PERL_OLE_ID, PERL_OLE_IDLEN,(
long
)coo));
if
(coo != NULL) {
lpObj = (LPWINOLEOBJECT)SvIV(*coo);
if
(ValidDispatch(lpObj) && lpObj->pEnum != NULL) {
VariantInit(&result);
bSuccess = lpObj->pEnum->Next(1, &result, NULL) == S_OK;
if
(!bSuccess) {
lpObj->pEnum->Release();
lpObj->pEnum = NULL;
}
}
}
if
(bSuccess)
SetSVFromVariant(&result, (ST(0) = sv_2mortal(newSVpv(
""
,0))));
else
ST(0) = &sv_undef;
XSRETURN(1);
}