You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1108 lines
22 KiB
1108 lines
22 KiB
/*++=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.cxx
|
|
|
|
Abstract:
|
|
|
|
Utility functions.
|
|
|
|
Author:
|
|
|
|
Paul M Midgen (pmidge) 12-October-2000
|
|
|
|
|
|
Revision History:
|
|
|
|
12-October-2000 pmidge
|
|
Created
|
|
|
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--*/
|
|
|
|
#include "common.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
const IID IID_IWinHttpRequest =
|
|
{
|
|
0x06f29373,
|
|
0x5c5a,
|
|
0x4b54,
|
|
{0xb0,0x25,0x6e,0xf1,0xbf,0x8a,0xbf,0x0e}
|
|
};
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// file retrieval
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
__PathIsUNC(LPCWSTR path)
|
|
{
|
|
BOOL bIsUNC = FALSE;
|
|
WCHAR* embedded = NULL;
|
|
|
|
// is the path a UNC share? e.g. \\foo\bar\baz.htm
|
|
if( wcsstr(path, L"\\\\") )
|
|
{
|
|
embedded = wcsstr(path, L"\\");
|
|
|
|
if( embedded && (wcslen(embedded) > 1) )
|
|
{
|
|
bIsUNC = TRUE;
|
|
}
|
|
}
|
|
else // how about a filesystem path, e.g. z:\foo\bar.htm
|
|
{
|
|
embedded = wcsstr(path, L":");
|
|
|
|
if( embedded && ((embedded-1) == path) )
|
|
{
|
|
bIsUNC = TRUE;
|
|
}
|
|
}
|
|
|
|
return bIsUNC;
|
|
}
|
|
|
|
BOOL
|
|
__PathIsURL(LPCWSTR path)
|
|
{
|
|
BOOL bIsURL = FALSE;
|
|
|
|
if( wcsstr(path, L"http") )
|
|
{
|
|
bIsURL = TRUE;
|
|
}
|
|
|
|
return bIsURL;
|
|
}
|
|
|
|
BOOL
|
|
GetFile(LPCWSTR path, HANDLE* phUNC, IWinHttpRequest** ppWHR, DWORD mode, BOOL* bReadOnly)
|
|
{
|
|
DEBUG_ENTER((
|
|
DBG_UTILS,
|
|
rt_bool,
|
|
"GetFile",
|
|
"path=%S; phUNC=%#x; ppWHR=%#x; mode=%#x; bReadOnly=%#x",
|
|
path,
|
|
phUNC,
|
|
ppWHR,
|
|
mode,
|
|
bReadOnly
|
|
));
|
|
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if( path )
|
|
{
|
|
if( phUNC )
|
|
{
|
|
*phUNC = __OpenFile(path, mode, bReadOnly);
|
|
|
|
if( *phUNC != INVALID_HANDLE_VALUE )
|
|
{
|
|
bSuccess = TRUE;
|
|
}
|
|
}
|
|
else if( ppWHR )
|
|
{
|
|
*ppWHR = __OpenUrl(path);
|
|
|
|
if( *ppWHR )
|
|
{
|
|
*bReadOnly = TRUE;
|
|
bSuccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(bSuccess);
|
|
return bSuccess;
|
|
}
|
|
|
|
HANDLE
|
|
__OpenFile(LPCWSTR path, DWORD mode, BOOL* bReadOnly)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD flags = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
retry:
|
|
|
|
hFile = CreateFile(
|
|
path,
|
|
flags,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
mode,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if( hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
if( GetLastError() == ERROR_ACCESS_DENIED )
|
|
{
|
|
if( flags == (GENERIC_READ | GENERIC_WRITE) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("read/write open attempt failed, retrying for read-only access"));
|
|
|
|
flags = GENERIC_READ;
|
|
*bReadOnly = TRUE;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
DEBUG_TRACE(UTILS, ("error opening %S: %s", path, MapErrorToString(GetLastError())));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_TRACE(UTILS, ("file opened"));
|
|
}
|
|
|
|
return hFile;
|
|
}
|
|
|
|
IWinHttpRequest*
|
|
__OpenUrl(LPCWSTR url)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWinHttpRequest* pWHR = NULL;
|
|
BSTR bstrVerb = SysAllocString(L"GET");
|
|
BSTR bstrUrl = SysAllocString(url);
|
|
LONG status = 0L;
|
|
CLSID clsid;
|
|
|
|
NEWVARIANT(var);
|
|
NEWVARIANT(async);
|
|
|
|
V_VT(&async) = VT_BOOL;
|
|
V_BOOL(&async) = FALSE;
|
|
|
|
hr = CLSIDFromProgID(L"WinHttp.WinHttpRequest.5", &clsid);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("failed to get WinHttpRequest CLSID from registry (%s)", MapHResultToString(hr)));
|
|
goto quit;
|
|
}
|
|
|
|
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IWinHttpRequest, (void**) &pWHR);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("CoCreateInstance for IID_IWinHttpRequest failed (%s)", MapHResultToString(hr)));
|
|
goto quit;
|
|
}
|
|
|
|
hr = pWHR->SetProxy(HTTPREQUEST_PROXYSETTING_PRECONFIG, var, var);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("failed to set proxy (%s)", MapHResultToString(hr)));
|
|
goto quit;
|
|
}
|
|
|
|
hr = pWHR->Open(bstrVerb, bstrUrl, async);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("failed to open %S (%s)", bstrUrl, MapHResultToString(hr)));
|
|
goto quit;
|
|
}
|
|
|
|
hr = pWHR->Send(var);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("failed to send request (%s)", MapHResultToString(hr)));
|
|
goto quit;
|
|
}
|
|
|
|
hr = pWHR->get_Status(&status);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("response status %d", status));
|
|
hr = (status == 200) ? S_OK : E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_TRACE(UTILS, ("failed to get response status (%s)", MapHResultToString(hr)));
|
|
}
|
|
|
|
quit:
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
SAFERELEASE(pWHR);
|
|
}
|
|
|
|
SAFEDELETEBSTR(bstrVerb);
|
|
SAFEDELETEBSTR(bstrUrl);
|
|
VariantClear(&var);
|
|
VariantClear(&async);
|
|
|
|
return pWHR;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// general utility functions
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
GetTypeInfoFromName(LPCOLESTR name, ITypeLib* ptl, ITypeInfo** ppti)
|
|
{
|
|
DEBUG_ENTER((
|
|
DBG_UTILS,
|
|
rt_hresult,
|
|
"GetTypeInfoFromName",
|
|
"name=%.16S; ptl=%#x; ppti=%#x",
|
|
name,
|
|
ptl,
|
|
ppti
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL bFound = FALSE;
|
|
USHORT cf = 1L;
|
|
ULONG hash = 0L;
|
|
LONG id = 0L;
|
|
LPOLESTR pstr = NULL;
|
|
|
|
if( !name || ! ptl )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto quit;
|
|
}
|
|
|
|
if( !ppti )
|
|
{
|
|
hr = E_POINTER;
|
|
goto quit;
|
|
}
|
|
|
|
*ppti = NULL;
|
|
pstr = __wstrdup(name);
|
|
|
|
ptl->IsName(pstr, 0L, &bFound);
|
|
|
|
if( !bFound )
|
|
{
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
goto quit;
|
|
}
|
|
|
|
hash = LHashValOfNameSys(
|
|
SYS_WIN32,
|
|
MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT),
|
|
pstr
|
|
);
|
|
|
|
hr = ptl->FindName(pstr, hash, ppti, &id, &cf);
|
|
|
|
DEBUG_TRACE(UTILS, ("find name: pti=%#x; cf=%d", *ppti, cf));
|
|
|
|
quit:
|
|
|
|
SAFEDELETEBUF(pstr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
BOOL
|
|
GetJScriptCLSID(LPCLSID pclsid)
|
|
{
|
|
DEBUG_ENTER((
|
|
DBG_UTILS,
|
|
rt_bool,
|
|
"GetJScriptCLSID",
|
|
"pclsid=%#x",
|
|
pclsid
|
|
));
|
|
|
|
BOOL ret = FALSE;
|
|
HKEY hk = NULL;
|
|
LPBYTE buf = NULL;
|
|
DWORD cb = 0L;
|
|
DWORD rt = REG_SZ;
|
|
|
|
if( RegOpenKey(HKEY_CLASSES_ROOT, L"JScript\\CLSID", &hk) == ERROR_SUCCESS )
|
|
{
|
|
if( RegQueryValueEx(hk, L"", NULL, &rt, NULL, &cb) == ERROR_SUCCESS )
|
|
{
|
|
buf = new BYTE[cb];
|
|
|
|
RegQueryValueEx(hk, L"", NULL, &rt, buf, &cb);
|
|
CLSIDFromString((LPOLESTR) buf, pclsid);
|
|
ret = TRUE;
|
|
|
|
SAFEDELETEBUF(buf);
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(ret);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
ParseSocketInfo(PIOCTX pi)
|
|
{
|
|
PSOCKADDR_IN pLocal = NULL;
|
|
PSOCKADDR_IN pRemote = NULL;
|
|
int cbLocal = 0;
|
|
int cbRemote = 0;
|
|
char* buf = NULL;
|
|
int len = 0;
|
|
int error = 0;
|
|
|
|
GetAcceptExSockaddrs(
|
|
pi->sockbuf, 0,
|
|
SOCKADDRBUFSIZE,
|
|
SOCKADDRBUFSIZE,
|
|
(PSOCKADDR*) &pLocal, &cbLocal,
|
|
(PSOCKADDR*) &pRemote, &cbRemote
|
|
);
|
|
|
|
pi->local = new HOSTINFO;
|
|
pi->remote = new HOSTINFO;
|
|
|
|
GetHostname(pLocal->sin_addr, &pi->local->name);
|
|
pi->local->addr = __strdup(inet_ntoa(pLocal->sin_addr));
|
|
pi->local->port = ntohs(pLocal->sin_port);
|
|
|
|
GetHostname(pRemote->sin_addr, &pi->remote->name);
|
|
pi->remote->addr = __strdup(inet_ntoa(pRemote->sin_addr));
|
|
pi->remote->port = ntohs(pRemote->sin_port);
|
|
|
|
if( !pi->remote->name )
|
|
{
|
|
pi->remote->name = __strdup(pi->remote->addr);
|
|
}
|
|
|
|
len = strlen(pi->remote->name)+7; // ":" plus 5 port digits and a null
|
|
buf = new char[len];
|
|
|
|
strncpy(buf, pi->remote->name, len);
|
|
strncat(buf, ":", sizeof(char));
|
|
_itoa(pi->remote->port, (buf+strlen(buf)), 10);
|
|
|
|
pi->clientid = __ansitowide(buf);
|
|
|
|
SAFEDELETEBUF(buf);
|
|
}
|
|
|
|
void
|
|
GetHostname(struct in_addr ip, LPSTR* ppsz)
|
|
{
|
|
HOSTENT* ph = NULL;
|
|
|
|
ph = gethostbyaddr(
|
|
(char*) &ip,
|
|
sizeof(struct in_addr),
|
|
AF_INET
|
|
);
|
|
|
|
if( ph )
|
|
{
|
|
*ppsz = __strdup(ph->h_name);
|
|
}
|
|
else
|
|
{
|
|
*ppsz = NULL;
|
|
}
|
|
}
|
|
|
|
DISPID
|
|
GetDispidFromName(PDISPIDTABLEENTRY pdt, DWORD cEntries, LPWSTR name)
|
|
{
|
|
DWORD n = 0L;
|
|
DWORD hash = GetHash(name);
|
|
DISPID dispid = DISPID_UNKNOWN;
|
|
|
|
while( n < cEntries )
|
|
{
|
|
if( pdt[n].hash != hash )
|
|
{
|
|
++n;
|
|
}
|
|
else
|
|
{
|
|
dispid = pdt[n].dispid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DEBUG_TRACE(DISPATCH, ("hash %#x is %s", hash, MapDispidToString(dispid)));
|
|
return dispid;
|
|
}
|
|
|
|
void
|
|
AddRichErrorInfo(EXCEPINFO* pei, LPWSTR source, LPWSTR description, HRESULT error)
|
|
{
|
|
if( pei )
|
|
{
|
|
pei->bstrSource = __widetobstr((source ? source : L"unknown source"));
|
|
pei->bstrDescription = __widetobstr((description ? description : L"no description"));
|
|
pei->scode = error;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
GetHash(LPWSTR name)
|
|
{
|
|
DWORD hash = 0L;
|
|
DWORD n = 0L;
|
|
DWORD len = 0L;
|
|
LPSTR string = NULL;
|
|
|
|
string = __widetoansi(name);
|
|
|
|
if( string )
|
|
{
|
|
_strlwr(string);
|
|
|
|
for(n=0, len=strlen(string); n<=len; n++)
|
|
{
|
|
hash += __toascii(string[len-n]) * ((10<<n)^n);
|
|
}
|
|
|
|
DEBUG_TRACE(DISPATCH, ("name=%s; hash=%#x", string, hash));
|
|
}
|
|
|
|
SAFEDELETEBUF(string);
|
|
return hash;
|
|
}
|
|
|
|
DWORD
|
|
GetHash(LPSTR name)
|
|
{
|
|
DWORD hash = 0L;
|
|
DWORD n = 0L;
|
|
DWORD len = 0L;
|
|
LPSTR string = NULL;
|
|
|
|
string = __strdup(name);
|
|
|
|
if( string )
|
|
{
|
|
_strlwr(string);
|
|
|
|
for(n=0, len=strlen(string); n<=len; n++)
|
|
{
|
|
hash += __toascii(string[len-n]) * ((10<<n)^n);
|
|
}
|
|
|
|
DEBUG_TRACE(DISPATCH, ("name=%s; hash=%#x", string, hash));
|
|
}
|
|
|
|
SAFEDELETEBUF(string);
|
|
return hash;
|
|
}
|
|
|
|
HRESULT
|
|
ProcessVariant(VARIANT* pvar, LPBYTE* ppbuf, LPDWORD pcbuf, LPDWORD pbytes)
|
|
{
|
|
DEBUG_ENTER((
|
|
DBG_UTILS,
|
|
rt_hresult,
|
|
"ProcessVariant",
|
|
"pvar=%#x; ppbuf=%#x; pcbuf=%#x; pbytes=%#x",
|
|
pvar,
|
|
ppbuf,
|
|
pcbuf,
|
|
pbytes
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
LPBYTE pbyte = NULL;
|
|
DWORD len = NULL;
|
|
BOOL bAlloc = FALSE;
|
|
BOOL bBypass = FALSE;
|
|
|
|
if( !ppbuf || !pcbuf )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// if the caller wants us to allocate storage, we don't need
|
|
// the pbytes parameter. otherwise, we do in case the caller
|
|
// needs to resize their buffer.
|
|
//
|
|
if( ((*ppbuf) && *pcbuf != 0) && !pbytes )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto quit;
|
|
}
|
|
|
|
if( !(*ppbuf) && *pcbuf == 0 )
|
|
{
|
|
DEBUG_TRACE(UTILS, ("will allocate storage for variant data"));
|
|
bAlloc = TRUE;
|
|
}
|
|
|
|
DEBUG_TRACE(
|
|
RUNTIME,
|
|
("variant type is %s", MapVariantTypeToString(pvar))
|
|
);
|
|
|
|
switch( V_VT(pvar) )
|
|
{
|
|
case VT_BSTR :
|
|
{
|
|
pbyte = (LPBYTE) __widetoansi(V_BSTR(pvar));
|
|
len = strlen((LPSTR) pbyte);
|
|
}
|
|
break;
|
|
|
|
case VT_ARRAY | VT_UI1 :
|
|
{
|
|
SAFEARRAY* psa = V_ARRAY(pvar);
|
|
LPBYTE ptmp = NULL;
|
|
|
|
hr = SafeArrayAccessData(psa, (void**) &ptmp);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
SafeArrayGetUBound(psa, 1, (long*) &len);
|
|
|
|
pbyte = new BYTE[len];
|
|
memcpy(pbyte, ptmp, len);
|
|
|
|
SafeArrayUnaccessData(psa);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_UNKNOWN :
|
|
{
|
|
hr = ProcessObject(pvar->punkVal, ppbuf, pcbuf, pbytes);
|
|
bBypass = TRUE;
|
|
}
|
|
break;
|
|
|
|
case VT_DISPATCH :
|
|
{
|
|
IUnknown* punk = NULL;
|
|
|
|
if( SUCCEEDED(pvar->pdispVal->QueryInterface(IID_IUnknown, (void**) &punk)) )
|
|
{
|
|
hr = ProcessObject(punk, ppbuf, pcbuf, pbytes);
|
|
bBypass = TRUE;
|
|
}
|
|
|
|
SAFERELEASE(punk);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//
|
|
// bBypass is set when we make a call into ProcessObject(), which
|
|
// always calls back into us to handle the unpacked non-object-type
|
|
// variant. in that nested call the buffers & length variables are
|
|
// set, so we bypass those operations when the outer call unwinds.
|
|
//
|
|
if( SUCCEEDED(hr) && !bBypass )
|
|
{
|
|
if( bAlloc )
|
|
{
|
|
*ppbuf = pbyte;
|
|
*pcbuf = len;
|
|
}
|
|
else
|
|
{
|
|
if( *pcbuf >= len )
|
|
{
|
|
memcpy(*ppbuf, pbyte, len);
|
|
*pbytes = len;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
*pcbuf = len;
|
|
}
|
|
|
|
SAFEDELETEBUF(pbyte);
|
|
}
|
|
}
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// WARNING: do not modify these values. use disphash.exe to generate
|
|
// new values.
|
|
//
|
|
#define CLASS_HASH_URL 0x0000417f
|
|
#define CLASS_HASH_ENTITY 0x000213d4
|
|
#define CLASS_HASH_HEADERS 0x000401cd
|
|
|
|
HRESULT
|
|
ProcessObject(IUnknown* punk, LPBYTE* ppbuf, LPDWORD pcbuf, LPDWORD pbytes)
|
|
{
|
|
DEBUG_ENTER((
|
|
DBG_UTILS,
|
|
rt_hresult,
|
|
"ProcessObject",
|
|
"punk=%#x",
|
|
punk
|
|
));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
IProvideClassInfo* pci = NULL;
|
|
IW3SpoofFile* pfile = NULL;
|
|
|
|
// first try to use class information to determine what was
|
|
// passed in. all om objects support this method.
|
|
|
|
//
|
|
// BUGBUG: potential failure case is when objects are "torn off" from
|
|
// their parents (e.g. persisted through the runtime property bag).
|
|
// in that scenario the objects lose site information and therefore
|
|
// aren't able to look up their typeinfo. fix is to cache typeinfo
|
|
// during object creation.
|
|
//
|
|
// workitem filed IEv6 #21277
|
|
//
|
|
hr = punk->QueryInterface(IID_IProvideClassInfo, (void**) &pci);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
ITypeInfo* pti = NULL;
|
|
IEntity* pentity = NULL;
|
|
IHeaders* pheaders = NULL;
|
|
IUrl* purl = NULL;
|
|
BSTR name = NULL;
|
|
NEWVARIANT(tmp);
|
|
|
|
if( SUCCEEDED(pci->GetClassInfo(&pti)) )
|
|
{
|
|
pti->GetDocumentation(MEMBERID_NIL, &name, NULL, NULL, NULL);
|
|
|
|
DEBUG_TRACE(SOCKET, ("processing an %S object", name));
|
|
|
|
switch( GetHash(name) )
|
|
{
|
|
case CLASS_HASH_URL :
|
|
{
|
|
if( SUCCEEDED(punk->QueryInterface(IID_IUrl, (void**) &purl)) )
|
|
{
|
|
if( SUCCEEDED(purl->Get(&V_BSTR(&tmp))) )
|
|
{
|
|
V_VT(&tmp) = VT_BSTR;
|
|
hr = ProcessVariant(&tmp, ppbuf, pcbuf, pbytes);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CLASS_HASH_HEADERS :
|
|
{
|
|
if( SUCCEEDED(punk->QueryInterface(IID_IHeaders, (void**) &pheaders)) )
|
|
{
|
|
if( SUCCEEDED(pheaders->Get(&V_BSTR(&tmp))) )
|
|
{
|
|
V_VT(&tmp) = VT_BSTR;
|
|
hr = ProcessVariant(&tmp, ppbuf, pcbuf, pbytes);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CLASS_HASH_ENTITY :
|
|
{
|
|
if( SUCCEEDED(punk->QueryInterface(IID_IEntity, (void**) &pentity)) )
|
|
{
|
|
if( SUCCEEDED(pentity->Get(&tmp)) )
|
|
{
|
|
hr = ProcessVariant(&tmp, ppbuf, pcbuf, pbytes);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
SAFERELEASE(pti);
|
|
SAFERELEASE(purl);
|
|
SAFERELEASE(pentity);
|
|
SAFERELEASE(pheaders);
|
|
SAFEDELETEBSTR(name);
|
|
VariantClear(&tmp);
|
|
}
|
|
|
|
SAFERELEASE(pci);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
// try IW3SpoofFile...
|
|
hr = punk->QueryInterface(IID_IW3SpoofFile, (void**) &pfile);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
NEWVARIANT(tmp);
|
|
|
|
DEBUG_TRACE(SOCKET, ("processing an IW3SpoofFile object"));
|
|
|
|
hr = pfile->ReadAll(&tmp);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = ProcessVariant(&tmp, ppbuf, pcbuf, pbytes);
|
|
}
|
|
|
|
SAFERELEASE(pfile);
|
|
VariantClear(&tmp);
|
|
}
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ValidateDispatchArgs(REFIID riid, DISPPARAMS* pdp, VARIANT* pvr, UINT* pae)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if( !IsEqualIID(riid, IID_NULL) )
|
|
{
|
|
hr = DISP_E_UNKNOWNINTERFACE;
|
|
goto quit;
|
|
}
|
|
|
|
if( !pdp )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto quit;
|
|
}
|
|
|
|
if( pae )
|
|
{
|
|
*pae = 0;
|
|
}
|
|
|
|
if( pvr )
|
|
{
|
|
VariantInit(pvr);
|
|
}
|
|
|
|
quit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ValidateInvokeFlags(WORD flags, WORD accesstype, BOOL bNotMethod)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if( (flags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT)) )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
if( bNotMethod )
|
|
{
|
|
if( flags & DISPATCH_METHOD )
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
else
|
|
{
|
|
if( (flags & DISPATCH_PROPERTYPUT) && !(accesstype & DISPATCH_PROPERTYPUT) )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
if( !(flags & accesstype) )
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( flags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET) )
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ValidateArgCount(DISPPARAMS* pdp, DWORD needed, BOOL bHasOptionalArgs, DWORD optional)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if( bHasOptionalArgs )
|
|
{
|
|
if( (pdp->cArgs > needed+optional) || (pdp->cArgs < needed) )
|
|
{
|
|
hr = DISP_E_BADPARAMCOUNT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (!needed && pdp->cArgs) || (needed < pdp->cArgs) )
|
|
{
|
|
hr = DISP_E_BADPARAMCOUNT;
|
|
}
|
|
else
|
|
{
|
|
hr = (pdp->cArgs == needed) ? S_OK : DISP_E_PARAMNOTOPTIONAL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HandleDispatchError(LPWSTR id, EXCEPINFO* pei, HRESULT hr)
|
|
{
|
|
LPWSTR msg = NULL;
|
|
|
|
switch( hr )
|
|
{
|
|
case E_POINTER : msg = L"a return pointer parameter was missing"; break;
|
|
case E_ACCESSDENIED : msg = L"attempt to modify object failed because it is read-only"; break;
|
|
case E_FAIL : msg = L"an unhandled error occurred"; break;
|
|
case E_INVALIDARG : msg = L"an argument passed to a property or method was invalid"; break;
|
|
case E_NOINTERFACE : msg = L"a property or method was accessed incorrectly"; break;
|
|
default : return hr;
|
|
}
|
|
|
|
AddRichErrorInfo(pei, id, msg, hr);
|
|
|
|
return DISP_E_EXCEPTION;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// string & type manipulation
|
|
//-----------------------------------------------------------------------------
|
|
char*
|
|
__strdup(const char* src)
|
|
{
|
|
int n = 0;
|
|
char* dup = NULL;
|
|
|
|
if( src )
|
|
{
|
|
n = strlen(src)+1;
|
|
dup = new char[n];
|
|
strncpy(dup, src, n);
|
|
}
|
|
|
|
return dup;
|
|
}
|
|
|
|
char*
|
|
__strndup(const char* src, int len)
|
|
{
|
|
char* dup = NULL;
|
|
|
|
if( src )
|
|
{
|
|
dup = new char[len+1];
|
|
dup[len] = '\0';
|
|
strncpy(dup, src, len);
|
|
}
|
|
|
|
return dup;
|
|
}
|
|
|
|
WCHAR*
|
|
__wstrdup(const WCHAR* src)
|
|
{
|
|
int n = 0;
|
|
WCHAR* dup = NULL;
|
|
|
|
if( src )
|
|
{
|
|
n = wcslen(src)+1;
|
|
dup = new WCHAR[n];
|
|
wcsncpy(dup, src, n);
|
|
}
|
|
|
|
return dup;
|
|
}
|
|
|
|
WCHAR*
|
|
__wstrndup(const WCHAR* src, int len)
|
|
{
|
|
WCHAR* dup = NULL;
|
|
|
|
if( src )
|
|
{
|
|
dup = new WCHAR[len+1];
|
|
dup[len] = L'\0';
|
|
wcsncpy(dup, src, len);
|
|
}
|
|
|
|
return dup;
|
|
}
|
|
|
|
WCHAR*
|
|
__ansitowide(const char* psz)
|
|
{
|
|
WCHAR* wide = NULL;
|
|
int len = 0L;
|
|
|
|
if( psz )
|
|
{
|
|
len = strlen(psz);
|
|
|
|
if( len )
|
|
{
|
|
++len;
|
|
wide = new WCHAR[len];
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
psz,
|
|
len,
|
|
wide,
|
|
len
|
|
);
|
|
}
|
|
}
|
|
|
|
return wide;
|
|
}
|
|
|
|
CHAR*
|
|
__widetoansi(const WCHAR* pwsz)
|
|
{
|
|
CHAR* ansi = NULL;
|
|
int len = 0L;
|
|
BOOL def = FALSE;
|
|
|
|
if( pwsz )
|
|
{
|
|
len = wcslen(pwsz);
|
|
|
|
if( len )
|
|
{
|
|
++len;
|
|
ansi = new CHAR[len];
|
|
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pwsz,
|
|
len,
|
|
ansi,
|
|
len,
|
|
"?",
|
|
&def
|
|
);
|
|
}
|
|
}
|
|
|
|
return ansi;
|
|
}
|
|
|
|
BSTR
|
|
__ansitobstr(LPCSTR src)
|
|
{
|
|
BSTR ret = NULL;
|
|
LPWSTR wsz = NULL;
|
|
|
|
if( src )
|
|
{
|
|
wsz = __ansitowide(src);
|
|
ret = SysAllocString(wsz);
|
|
SAFEDELETEBUF(wsz);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
BSTR
|
|
__widetobstr(LPCWSTR wsrc)
|
|
{
|
|
return (wsrc ? SysAllocString(wsrc) : NULL);
|
|
}
|
|
|
|
BOOL
|
|
__isempty(VARIANT var)
|
|
{
|
|
BOOL isempty = FALSE;
|
|
|
|
if(
|
|
((V_VT(&var) == VT_EMPTY) || (V_VT(&var) == VT_NULL) || (V_VT(&var) == VT_ERROR)) ||
|
|
((V_VT(&var) == VT_BSTR) && (SysStringLen(V_BSTR(&var)) == 0))
|
|
)
|
|
{
|
|
isempty = TRUE;
|
|
}
|
|
|
|
return isempty;
|
|
}
|
|
|
|
// private
|
|
char hex2char(char* hex)
|
|
{
|
|
register char digit;
|
|
|
|
digit = (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
|
|
digit *= 16;
|
|
digit += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
|
|
|
|
return(digit);
|
|
}
|
|
|
|
char*
|
|
__unescape(char* str)
|
|
{
|
|
register int x;
|
|
register int y;
|
|
char* str2;
|
|
|
|
str2 = __strdup(str);
|
|
|
|
if( str2 )
|
|
{
|
|
for(x=0, y=0; str2[y]; ++x, ++y)
|
|
{
|
|
if((str2[x] = str2[y]) == '%')
|
|
{
|
|
str2[x] = hex2char(&str2[y+1]);
|
|
y += 2;
|
|
}
|
|
}
|
|
|
|
str2[x] = '\0';
|
|
}
|
|
|
|
return str2;
|
|
}
|