windows-nt/Source/XPSP1/NT/shell/ext/ftp/dspsprt.cpp
2020-09-26 16:20:57 +08:00

479 lines
12 KiB
C++

#include "priv.h"
#include "dspsprt.h"
#include "msieftp.h"
#define TF_IDISPATCH 0
/*
* CImpIDispatch::CImpIDispatch
* CImpIDispatch::~CImpIDispatch
*
* Parameters (Constructor):
* piid guid this IDispatch implementation is for
* we call QueryInterface to get the interface
*/
CImpIDispatch::CImpIDispatch(const IID * piid)
{
// TraceMsg(TF_ALWAYS, "ctor CImpIDispatch %x", this);
m_piid = piid;
ASSERT(NULL==m_pITINeutral);
ASSERT(NULL==m_pdisp);
return;
}
CImpIDispatch::~CImpIDispatch(void)
{
// TraceMsg(TF_ALWAYS, "dtor CImpIDispatch %x", this);
if (m_pITINeutral)
{
m_pITINeutral->Release();
m_pITINeutral = NULL;
}
return;
}
/*
* CImpIDispatch::GetTypeInfoCount
*
* Purpose:
* Returns the number of type information (ITypeInfo) interfaces
* that the object provides (0 or 1).
*
* Parameters:
* pctInfo UINT * to the location to receive
* the count of interfaces.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
{
//We implement GetTypeInfo so return 1
*pctInfo=1;
return NOERROR;
}
//
// helper function for pulling ITypeInfo out of our typelib
//
HRESULT MSIEFTPGetTypeInfo(LCID lcid, UUID uuid, ITypeInfo **ppITypeInfo)
{
HRESULT hr;
ITypeLib *pITypeLib;
// Just in case we can't find the type library anywhere
*ppITypeInfo = NULL;
/*
* The type libraries are registered under 0 (neutral),
* 7 (German), and 9 (English) with no specific sub-
* language, which would make them 407 or 409 and such.
* If you are sensitive to sub-languages, then use the
* full LCID instead of just the LANGID as done here.
*/
hr=LoadRegTypeLib(LIBID_MSIEFTPLib, 1, 0, PRIMARYLANGID(lcid), &pITypeLib);
/*
* If LoadRegTypeLib fails, try loading directly with
* LoadTypeLib, which will register the library for us.
* Note that there's no default case here because the
* prior switch will have filtered lcid already.
*
* NOTE: You should prepend your DIR registry key to the
* .TLB name so you don't depend on it being it the PATH.
* This sample will be updated later to reflect this.
*/
if (FAILED(hr))
{
OLECHAR wszPath[MAX_PATH];
#ifdef UNICODE
GetModuleFileName(HINST_THISDLL, wszPath, ARRAYSIZE(wszPath));
#else
TCHAR szPath[MAX_PATH];
GetModuleFileName(HINST_THISDLL, szPath, ARRAYSIZE(szPath));
MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath));
#endif
switch (PRIMARYLANGID(lcid))
{
case LANG_NEUTRAL:
case LANG_ENGLISH:
hr=LoadTypeLib(wszPath, &pITypeLib);
break;
}
}
if (SUCCEEDED(hr))
{
//Got the type lib, get type info for the interface we want
hr=pITypeLib->GetTypeInfoOfGuid(uuid, ppITypeInfo);
pITypeLib->Release();
}
return(hr);
}
/*
* CImpIDispatch::GetTypeInfo
*
* Purpose:
* Retrieves type information for the automation interface. This
* is used anywhere that the right ITypeInfo interface is needed
* for whatever LCID is applicable. Specifically, this is used
* from within GetIDsOfNames and Invoke.
*
* Parameters:
* itInfo UINT reserved. Must be zero.
* lcid LCID providing the locale for the type
* information. If the object does not support
* localization, this is ignored.
* ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
* interface for the object.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid
, ITypeInfo **ppITypeInfo)
{
ITypeInfo **ppITI;
*ppITypeInfo=NULL;
if (0!=itInfo)
return(TYPE_E_ELEMENTNOTFOUND);
#if 1
// docs say we can ignore lcid if we support only one LCID
// we don't have to return DISP_E_UNKNOWNLCID if we're *ignoring* it
ppITI = &m_pITINeutral;
#else
/*
* Since we returned one from GetTypeInfoCount, this function
* can be called for a specific locale. We support English
* and neutral (defaults to English) locales. Anything
* else is an error.
*
* After this switch statement, ppITI will point to the proper
* member pITypeInfo. If *ppITI is NULL, we know we need to
* load type information, retrieve the ITypeInfo we want, and
* then store it in *ppITI.
*/
switch (PRIMARYLANGID(lcid))
{
case LANG_NEUTRAL:
case LANG_ENGLISH:
ppITI=&m_pITINeutral;
break;
default:
return(DISP_E_UNKNOWNLCID);
}
#endif
//Load a type lib if we don't have the information already.
if (NULL==*ppITI)
{
HRESULT hr;
ITypeInfo *pITIDisp;
hr = MSIEFTPGetTypeInfo(lcid, *m_piid, &pITIDisp);
if (SUCCEEDED(hr))
{
HRESULT hrT;
HREFTYPE hrefType;
// All our IDispatch implementations are DUAL. GetTypeInfoOfGuid
// returns the ITypeInfo of the IDispatch-part only. We need to
// find the ITypeInfo for the dual interface-part.
//
hrT = pITIDisp->GetRefTypeOfImplType(0xffffffff, &hrefType);
if (SUCCEEDED(hrT))
{
hrT = pITIDisp->GetRefTypeInfo(hrefType, ppITI);
}
ASSERT(SUCCEEDED(hrT));
if (FAILED(hrT))
{
// I suspect GetRefTypeOfImplType may fail if someone uses
// CImpIDispatch on a non-dual interface. In this case the
// ITypeInfo we got above is just fine to use.
//
*ppITI = pITIDisp;
}
else
{
pITIDisp->Release();
}
}
if (FAILED(hr))
return hr;
}
/*
* Note: the type library is still loaded since we have
* an ITypeInfo from it.
*/
(*ppITI)->AddRef();
*ppITypeInfo=*ppITI;
return NOERROR;
}
/*
* CImpIDispatch::GetIDsOfNames
*
* Purpose:
* Converts text names into DISPIDs to pass to Invoke
*
* Parameters:
* riid REFIID reserved. Must be IID_NULL.
* rgszNames OLECHAR ** pointing to the array of names to be
* mapped.
* cNames UINT number of names to be mapped.
* lcid LCID of the locale.
* rgDispID DISPID * caller allocated array containing IDs
* corresponging to those names in rgszNames.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
{
HRESULT hr;
ITypeInfo *pTI;
if (IID_NULL!=riid)
return(DISP_E_UNKNOWNINTERFACE);
//Get the right ITypeInfo for lcid.
hr=GetTypeInfo(0, lcid, &pTI);
if (SUCCEEDED(hr))
{
hr=pTI->GetIDsOfNames(rgszNames, cNames, rgDispID);
pTI->Release();
}
#ifdef DEBUG
char szParam[MAX_PATH] = "";
if (cNames >= 1)
{
WideCharToMultiByte(CP_ACP, 0,
*rgszNames, -1,
szParam, ARRAYSIZE(szParam), NULL, NULL);
}
TraceMsg(TF_IDISPATCH, "CImpIDispatch::GetIDsOfNames(%s = %x) called hres(%x)",
szParam, *rgDispID, hr);
#endif
return hr;
}
/*
* CImpIDispatch::Invoke
*
* Purpose:
* Calls a method in the dispatch interface or manipulates a
* property.
*
* Parameters:
* dispID DISPID of the method or property of interest.
* riid REFIID reserved, must be IID_NULL.
* lcid LCID of the locale.
* wFlags USHORT describing the context of the invocation.
* pDispParams DISPPARAMS * to the array of arguments.
* pVarResult VARIANT * in which to store the result. Is
* NULL if the caller is not interested.
* pExcepInfo EXCEPINFO * to exception information.
* puArgErr UINT * in which to store the index of an
* invalid parameter if DISP_E_TYPEMISMATCH
* is returned.
*
* Return Value:
* HRESULT NOERROR or a general error code.
*/
STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
, LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
ITypeInfo *pTI;
HRESULT hr;
//riid is supposed to be IID_NULL always
if (IID_NULL!=riid)
return(DISP_E_UNKNOWNINTERFACE);
// make sure we have an interface to hand off to Invoke
if (NULL == m_pdisp)
{
hr=QueryInterface(*m_piid, (LPVOID*)&m_pdisp);
if (!EVAL(SUCCEEDED(hr)))
return hr;
// don't hold a refcount on ourself
m_pdisp->Release();
}
//Get the ITypeInfo for lcid
hr=GetTypeInfo(0, lcid, &pTI);
if (SUCCEEDED(hr))
{
//Clear exceptions
SetErrorInfo(0L, NULL);
//This is exactly what DispInvoke does--so skip the overhead.
hr=pTI->Invoke(m_pdisp, dispID, wFlags
, pDispParams, pVarResult, pExcepInfo, puArgErr);
pTI->Release();
}
return hr;
}
/*
* CImpIDispatch::Exception
*
* Purpose:
* Raises an exception for CImpIDispatch::Invoke from within
* ITypeInfo::Invoke using the CreateErrorInfo API and the
* ICreateErrorInfo interface.
*
* Note that this method doesn't allow for deferred filling
* of an EXCEPINFO structure.
*
* Parameters:
* wException WORD exception code.
*/
void CImpIDispatch::Exception(WORD wException)
{
#if 0 // nobody calls this
ICreateErrorInfo *pICreateErr;
BOOL fSuccess;
LPTSTR psz;
LPOLESTR pszHelp;
UINT idsSource;
UINT idsException;
DWORD dwHelpID;
/*
* Thread-safe exception handling means that we call
* CreateErrorInfo which gives us an ICreateErrorInfo pointer
* that we then use to set the error information (basically
* to set the fields of an EXCEPINFO structure. We then
* call SetErrorInfo to attach this error to the current
* thread. ITypeInfo::Invoke will look for this when it
* returns from whatever function was invokes by calling
* GetErrorInfo.
*/
//Not much we can do if this fails.
if (FAILED(CreateErrorInfo(&pICreateErr)))
return;
psz=(LPTSTR)LocalAlloc(LPTR, 1024*sizeof(TCHAR));
// psz is a buffer to do LoadString()s into -- if we didn't
// get one then we won't get our error strings, so bail.
if (NULL==psz)
{
pICreateErr->Release();
return;
}
fSuccess=TRUE;
// typically you'd do a switch here on all the exception ids wException
// and fill in pszHelp, dwHelpID, idsSource, and idsException.
// if you mapped the exception id to valid strings, the code
// below will fill in the ICreateErr interface
//
switch (wException)
{
default:
fSuccess = FALSE;
}
if (fSuccess)
{
HRESULT hr;
IErrorInfo *pIErr;
/*
* If you have a help file, call the functions
* ICreateErrorInfo::SetHelpFile and
* ICreateErrorInfo::SetHelpContext as well. If you
* set the help file to NULL the context is ignored.
*/
pICreateErr->SetHelpFile(pszHelp);
pICreateErr->SetHelpContext(dwHelpID);
#ifndef UNICODE
OLECHAR szTemp[256];
LoadString(HINST_THISDLL, idsSource, psz, 256);
MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
pICreateErr->SetSource(szTemp);
LoadString(HINST_THISDLL, idsException, psz, 256);
MultiByteToWideChar(CP_ACP, 0, psz, -1, szTemp, 256);
pICreateErr->SetDescription(szTemp);
#else
LoadString(HINST_THISDLL, idsSource, psz, 1024);
pICreateErr->SetSource(psz);
LoadString(HINST_THISDLL, idsException, psz, 1024);
pICreateErr->SetDescription(psz);
#endif
hr=pICreateErr->QueryInterface(IID_IErrorInfo
, (LPVOID*)&pIErr);
if (SUCCEEDED(hr))
{
SetErrorInfo(0L, pIErr);
pIErr->Release();
}
}
LocalFree(psz);
//SetErrorInfo holds the object's IErrorInfo
pICreateErr->Release();
#endif
}