Leaked source code of windows server 2003
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.
 
 
 
 
 
 

895 lines
26 KiB

/*****************************************************************************\
FILE: AutoDiscMail.cpp
DESCRIPTION:
This is the Autmation Object to AutoDiscovered account information.
BryanSt 10/3/1999
Copyright (C) Microsoft Corp 1999-1999. All rights reserved.
\*****************************************************************************/
#include "priv.h"
#include <cowsite.h>
#include <atlbase.h>
#include "util.h"
#include "AutoDiscover.h"
#include "MailProtocol.h"
// TODO: Add " xmlns="http://bryanst2-email/dtd/AutoDiscovery" to XML"
#define XML_POST_REQUEST L"<?xml version=\"1.0\"?>\r\n" \
L"<" SZ_XMLELEMENT_AUTODISCOVERY L">\r\n" \
L"<" SZ_XMLELEMENT_REQUEST L">\r\n" \
L"<" SZ_XMLELEMENT_ACCOUNT L">\r\n" \
L"<" SZ_XMLELEMENT_TYPE L">" SZ_XMLTEXT_EMAIL L"</" SZ_XMLELEMENT_TYPE L">\r\n" \
L"<" SZ_XMLELEMENT_VERSION L">0.1</" SZ_XMLELEMENT_VERSION L">\r\n" \
L"<" SZ_XMLELEMENT_RESPONSEVER L">0.1</" SZ_XMLELEMENT_RESPONSEVER L">\r\n" \
L"<" SZ_XMLELEMENT_LANG L">en</" SZ_XMLELEMENT_LANG L">\r\n" \
L"<" SZ_XMLELEMENT_EMAIL L">%ls</" SZ_XMLELEMENT_EMAIL L">\r\n" \
L"</" SZ_XMLELEMENT_ACCOUNT L">\r\n" \
L"</" SZ_XMLELEMENT_REQUEST L">\r\n" \
L"</" SZ_XMLELEMENT_AUTODISCOVERY L">\r\n"
#define STR_AT_EMAIL TEXT("Email")
typedef struct tagPROTOCOL_ENTRY
{
BSTR bstrProtocolName;
IMailProtocolADEntry * pMailProtocol;
} PROTOCOL_ENTRY;
class CMailAccountDiscovery : public CAccountDiscoveryBase
, public CImpIDispatch
, public IMailAutoDiscovery
{
public:
//////////////////////////////////////////////////////
// Public Interfaces
//////////////////////////////////////////////////////
// *** IUnknown ***
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
virtual STDMETHODIMP_(ULONG) AddRef(void) {return CAccountDiscoveryBase::AddRef();}
virtual STDMETHODIMP_(ULONG) Release(void) {return CAccountDiscoveryBase::Release();}
// *** IMailAutoDiscovery ***
virtual STDMETHODIMP get_DisplayName(OUT BSTR * pbstr);
virtual STDMETHODIMP get_InfoURL(OUT BSTR * pbstrURL);
virtual STDMETHODIMP get_PreferedProtocolType(OUT BSTR * pbstrProtocolType);
virtual STDMETHODIMP get_length(OUT long * pnLength);
virtual STDMETHODIMP get_item(IN VARIANT varIndex, OUT IMailProtocolADEntry ** ppMailProtocol);
virtual STDMETHODIMP get_XML(OUT IXMLDOMDocument ** ppXMLDoc);
virtual STDMETHODIMP put_XML(IN IXMLDOMDocument * pXMLDoc);
virtual STDMETHODIMP getPrimaryProviders(IN BSTR bstrEmailAddress, OUT IAutoDiscoveryProvider ** ppProviders);
virtual STDMETHODIMP getSecondaryProviders(IN BSTR bstrEmailAddress, OUT IAutoDiscoveryProvider ** ppProviders);
virtual STDMETHODIMP DiscoverMail(IN BSTR bstrEmailAddress);
virtual STDMETHODIMP PurgeCache(void);
virtual STDMETHODIMP WorkAsync(IN HWND hwnd, IN UINT wMsg) {return _WorkAsync(hwnd, wMsg);}
// *** IDispatch ***
virtual STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
virtual STDMETHODIMP GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
virtual STDMETHODIMP GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid) { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
virtual STDMETHODIMP Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,UINT * puArgErr) { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
private:
CMailAccountDiscovery();
virtual ~CMailAccountDiscovery(void);
HRESULT _GetUsersDisplayName(IN IXMLDOMElement * pXMLElementMessage);
HRESULT _GetInfoURL(IN IXMLDOMNode * pXMLAccountNode);
HRESULT _Initialize(IN IXMLDOMElement * pXMLElementMessage);
HRESULT _FreeProtocolList(void);
HRESULT _CreateProtocolEntry(IN IXMLDOMNode * pXMLNodeProtocol);
HRESULT _GenerateXMLRequest(IN BSTR bstrEmailAddress, OUT BSTR * pbstrXMLRequest);
HRESULT _ParseResponse(void);
STDMETHODIMP _AsyncParseResponse(BSTR bstrEmail); // Override base class implementation
HRESULT _AsyncPrep(void);
// Private Member Variables
int m_cRef;
bool m_fDiscovered;
BSTR m_bstrUserDisplayName; // OPTIONAL: User's Display Name from server.
BSTR m_bstrInfoURL; // OPTIONAL: An URL pointing to a web page describing information about the e-mail server or accessing e-mail.
IXMLDOMNode * m_pXMLNodeAccount; // Node to section of XML with <ACCOUT> <TYPE>email</TYPE> ... </ACCOUNT>
IXMLDOMDocument * m_pXMLDocResponse; // The XML document
BSTR m_bstrResponse; // Cached XML response until the main thread can parse in the async case.
HDSA m_hdsaProtocols; // PROTOCOL_ENTRY structs, containing IMailAutoDiscoveryProtocol *.
// Friend Functions
friend HRESULT CMailAccountDiscovery_CreateInstance(IN IUnknown * punkOuter, REFIID riid, void ** ppvObj);
};
#define SZ_FILEEXTENSION L".xml"
//===========================
// *** Class Internals & Helpers ***
//===========================
HRESULT CMailAccountDiscovery::_GetUsersDisplayName(IN IXMLDOMElement * pXMLElementMessage)
{
IXMLDOMNode * pNodeUser;
HRESULT hr = XMLNode_GetChildTag(pXMLElementMessage, SZ_XMLELEMENT_USER, &pNodeUser);
if (m_bstrUserDisplayName)
{
SysFreeString(m_bstrUserDisplayName);
m_bstrUserDisplayName = NULL;
}
if (SUCCEEDED(hr))
{
hr = XMLNode_GetChildTagTextValue(pNodeUser, SZ_XMLELEMENT_DISPLAYNAME, &m_bstrUserDisplayName);
pNodeUser->Release();
}
return hr;
}
HRESULT CMailAccountDiscovery::_GetInfoURL(IN IXMLDOMNode * pXMLAccountNode)
{
if (m_bstrInfoURL)
{
SysFreeString(m_bstrInfoURL);
m_bstrInfoURL = NULL;
}
return XMLNode_GetChildTagTextValue(pXMLAccountNode, SZ_XMLELEMENT_INFOURL, &m_bstrInfoURL);
}
HRESULT CMailAccountDiscovery::_Initialize(IN IXMLDOMElement * pXMLElementMessage)
{
// This is only valid XML if the root tag is "AUTODISCOVERY".
// The case is not important.
// If it isn't we need to reject this return value.
// This happens most often when the URL fails to load
// because the server doesn't exist and the Web Proxy
// returns the error value wrapped in a web page.
HRESULT hr = XMLElem_VerifyTagName(pXMLElementMessage, SZ_XMLELEMENT_AUTODISCOVERY);
if (SUCCEEDED(hr))
{
IXMLDOMNode * pXMLReponse;
// We don't care if this is failes because the server isn't obligated to
// provide:
// <USER> <DISPLAYNAME> xxx </DISPLAYNAME> </USER>
_GetUsersDisplayName(pXMLElementMessage);
// Enter the <RESPONSE> tag.
hr = XMLNode_GetChildTag(pXMLElementMessage, SZ_XMLELEMENT_RESPONSE, &pXMLReponse);
if (SUCCEEDED(hr))
{
IXMLDOMElement * pXMLElementMessage;
hr = pXMLReponse->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pXMLElementMessage));
if (SUCCEEDED(hr))
{
IXMLDOMNodeList * pNodeListAccounts;
// Iterate thru the list of <ACCOUNT> tags...
hr = XMLElem_GetElementsByTagName(pXMLElementMessage, SZ_XMLELEMENT_ACCOUNT, &pNodeListAccounts);
if (SUCCEEDED(hr))
{
DWORD dwIndex = 0;
// We are going to look thru each one for one of them with <TYPE>email</TYPE>
while (S_OK == (hr = XMLNodeList_GetChild(pNodeListAccounts, dwIndex, &m_pXMLNodeAccount)))
{
// FUTURE: We could support redirects or error messages here depending on
// <ACTION> redirect | message </ACTION>
if (XML_IsChildTagTextEqual(m_pXMLNodeAccount, SZ_XMLELEMENT_TYPE, SZ_XMLTEXT_EMAIL))
{
// This file may or may not settings to contact the server. However in either case
// it may contain an INFOURL tag. If it does, then the URL in side will point to a
// web page.
// <INFOURL> xxx </INFOURL>
_GetInfoURL(m_pXMLNodeAccount);
if (XML_IsChildTagTextEqual(m_pXMLNodeAccount, SZ_XMLELEMENT_ACTION, SZ_XMLTEXT_SETTINGS))
{
break;
}
}
// No, so keep looking.
ATOMICRELEASE(m_pXMLNodeAccount);
dwIndex++;
}
pNodeListAccounts->Release();
}
pXMLElementMessage->Release();
}
pXMLReponse->Release();
}
}
return hr;
}
HRESULT CMailAccountDiscovery::_GenerateXMLRequest(IN BSTR bstrEmailAddress, OUT BSTR * pbstrXMLRequest)
{
HRESULT hr;
WCHAR wzXML[4096];
wnsprintfW(wzXML, ARRAYSIZE(wzXML), XML_POST_REQUEST, bstrEmailAddress);
hr = HrSysAllocStringW(wzXML, pbstrXMLRequest);
return hr;
}
HRESULT CMailAccountDiscovery::_CreateProtocolEntry(IN IXMLDOMNode * pXMLNodeProtocol)
{
BSTR bstrProtocolType;
HRESULT hr = XMLNode_GetChildTagTextValue(pXMLNodeProtocol, SZ_XMLELEMENT_TYPE, &bstrProtocolType);
if (SUCCEEDED(hr))
{
IMailProtocolADEntry * pMailProtocol;
hr = CMailProtocol_CreateInstance(pXMLNodeProtocol, &pMailProtocol);
if (SUCCEEDED(hr))
{
PROTOCOL_ENTRY protocolEntry;
protocolEntry.bstrProtocolName = bstrProtocolType;
protocolEntry.pMailProtocol = pMailProtocol;
if (-1 != DSA_InsertItem(m_hdsaProtocols, DA_LAST, &protocolEntry))
{
// We succeeded, so transfer owner ship of the items to the structure.
bstrProtocolType = NULL;
pMailProtocol = NULL;
}
else
{
hr = E_FAIL;
}
ATOMICRELEASE(pMailProtocol);
}
SysFreeString(bstrProtocolType);
}
return hr;
}
HRESULT CMailAccountDiscovery::_ParseResponse(void)
{
HRESULT hr = E_UNEXPECTED;
if (m_pXMLDocResponse)
{
IXMLDOMElement * pXMLElementMessage = NULL;
hr = m_pXMLDocResponse->get_documentElement(&pXMLElementMessage);
if (S_FALSE == hr)
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
else if (SUCCEEDED(hr))
{
hr = _Initialize(pXMLElementMessage);
if (SUCCEEDED(hr))
{
IXMLDOMNodeList * pNodeListProtocols;
// Iterate thru the list of <ACCOUNT> tags...
hr = XMLElem_GetElementsByTagName(pXMLElementMessage, SZ_XMLELEMENT_PROTOCOL, &pNodeListProtocols);
if (SUCCEEDED(hr))
{
IXMLDOMNode * pXMLNodeProtocol;
DWORD dwIndex;
for (dwIndex = 0; (S_OK == (hr = XMLNodeList_GetChild(pNodeListProtocols, dwIndex, &pXMLNodeProtocol))); dwIndex++)
{
hr = _CreateProtocolEntry(pXMLNodeProtocol);
pXMLNodeProtocol->Release();
}
long nCount;
if (SUCCEEDED(get_length(&nCount)) && (nCount > 0))
{
hr = S_OK;
}
pNodeListProtocols->Release();
}
}
pXMLElementMessage->Release();
}
}
return hr;
}
HRESULT CMailAccountDiscovery::_FreeProtocolList(void)
{
if (m_hdsaProtocols)
{
for (int nIndex = 0; nIndex < DSA_GetItemCount(m_hdsaProtocols); nIndex++)
{
PROTOCOL_ENTRY * pProtocolStruct = (PROTOCOL_ENTRY *) DSA_GetItemPtr(m_hdsaProtocols, nIndex);
if (pProtocolStruct)
{
SysFreeString(pProtocolStruct->bstrProtocolName);
ATOMICRELEASE(pProtocolStruct->pMailProtocol);
}
}
DSA_DeleteAllItems(m_hdsaProtocols);
}
return S_OK;
}
//===========================
// *** IMailAutoDiscovery Interface ***
//===========================
HRESULT CMailAccountDiscovery::get_DisplayName(OUT BSTR * pbstr)
{
HRESULT hr = E_INVALIDARG;
if (pbstr)
{
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
if (m_bstrUserDisplayName)
{
hr = HrSysAllocString(m_bstrUserDisplayName, pbstr);
}
else
{
*pbstr = NULL;
hr = E_FAIL;
}
}
}
return hr;
}
HRESULT CMailAccountDiscovery::get_InfoURL(OUT BSTR * pbstrURL)
{
HRESULT hr = E_INVALIDARG;
if (pbstrURL)
{
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
if (m_bstrInfoURL)
{
hr = HrSysAllocString(m_bstrInfoURL, pbstrURL);
}
else
{
*pbstrURL = NULL;
hr = E_FAIL;
}
}
}
return hr;
}
HRESULT CMailAccountDiscovery::get_PreferedProtocolType(OUT BSTR * pbstrProtocolType)
{
HRESULT hr = E_INVALIDARG;
if (pbstrProtocolType)
{
*pbstrProtocolType = NULL;
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
hr = E_FAIL;
if (m_hdsaProtocols && (0 < DSA_GetItemCount(m_hdsaProtocols)))
{
PROTOCOL_ENTRY * pProtocolEntry = (PROTOCOL_ENTRY *) DSA_GetItemPtr(m_hdsaProtocols, 0);
if (pProtocolEntry && pProtocolEntry->bstrProtocolName)
{
hr = HrSysAllocString(pProtocolEntry->bstrProtocolName, pbstrProtocolType);
}
}
}
}
return hr;
}
HRESULT CMailAccountDiscovery::get_length(OUT long * pnLength)
{
HRESULT hr = E_INVALIDARG;
if (pnLength)
{
*pnLength = 0;
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
*pnLength = (long) DSA_GetItemCount(m_hdsaProtocols);
hr = S_OK;
}
}
return hr;
}
HRESULT CMailAccountDiscovery::get_item(IN VARIANT varIndex, OUT IMailProtocolADEntry ** ppMailProtocol)
{
HRESULT hr = E_INVALIDARG;
if (ppMailProtocol)
{
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
long nCount = 0;
get_length(&nCount);
*ppMailProtocol = NULL;
hr = E_FAIL;
// This is sortof gross, but if we are passed a pointer to another variant, simply
// update our copy here...
if (varIndex.vt == (VT_BYREF | VT_VARIANT) && varIndex.pvarVal)
varIndex = *(varIndex.pvarVal);
switch (varIndex.vt)
{
case VT_I2:
varIndex.lVal = (long)varIndex.iVal;
// And fall through...
case VT_I4:
if ((varIndex.lVal >= 0) && (varIndex.lVal < nCount) && (0 < DSA_GetItemCount(m_hdsaProtocols)))
{
PROTOCOL_ENTRY * pProtocolEntry = (PROTOCOL_ENTRY *) DSA_GetItemPtr(m_hdsaProtocols, varIndex.lVal);
if (pProtocolEntry && pProtocolEntry->pMailProtocol)
{
hr = pProtocolEntry->pMailProtocol->QueryInterface(IID_PPV_ARG(IMailProtocolADEntry, ppMailProtocol));
}
}
break;
case VT_BSTR:
{
long nIndex;
for (nIndex = 0; nIndex < nCount; nIndex++)
{
PROTOCOL_ENTRY * pProtocolEntry = (PROTOCOL_ENTRY *) DSA_GetItemPtr(m_hdsaProtocols, nIndex);
if (pProtocolEntry && pProtocolEntry->pMailProtocol && pProtocolEntry->bstrProtocolName &&
!StrCmpIW(pProtocolEntry->bstrProtocolName, varIndex.bstrVal))
{
hr = pProtocolEntry->pMailProtocol->QueryInterface(IID_PPV_ARG(IMailProtocolADEntry, ppMailProtocol));
break;
}
}
}
break;
default:
hr = E_NOTIMPL;
}
}
}
return hr;
}
HRESULT CMailAccountDiscovery::get_XML(OUT IXMLDOMDocument ** ppXMLDoc)
{
HRESULT hr = E_INVALIDARG;
if (ppXMLDoc && m_pXMLDocResponse)
{
*ppXMLDoc = NULL;
hr = _AsyncPrep();
if (SUCCEEDED(hr))
{
hr = m_pXMLDocResponse->QueryInterface(IID_PPV_ARG(IXMLDOMDocument, ppXMLDoc));
}
}
return hr;
}
HRESULT CMailAccountDiscovery::put_XML(IN IXMLDOMDocument * pXMLDoc)
{
HRESULT hr = E_INVALIDARG;
return hr;
}
HRESULT _IsValidEmailAddress(IN BSTR bstrEmailAddress)
{
HRESULT hr = E_INVALIDARG;
if (bstrEmailAddress && bstrEmailAddress[0])
{
if (NULL != StrChrW(bstrEmailAddress, CH_EMAIL_AT))
{
// Ok, we found a '@' so it's valid.
hr = S_OK;
}
}
return hr;
}
HRESULT CMailAccountDiscovery::getPrimaryProviders(IN BSTR bstrEmailAddress, OUT IAutoDiscoveryProvider ** ppProviders)
{
return _getPrimaryProviders(bstrEmailAddress, ppProviders);
}
HRESULT CMailAccountDiscovery::getSecondaryProviders(IN BSTR bstrEmailAddress, OUT IAutoDiscoveryProvider ** ppProviders)
{
return _getSecondaryProviders(bstrEmailAddress, ppProviders, (ADDN_DEFAULT | ADDN_CONFIGURE_EMAIL_FALLBACK | ADDN_FILTER_EMAIL));
}
HRESULT CMailAccountDiscovery::DiscoverMail(IN BSTR bstrEmailAddress)
{
HRESULT hr = _IsValidEmailAddress(bstrEmailAddress);
if (SUCCEEDED(hr))
{
BSTR bstrXMLRequest;
hr = _GenerateXMLRequest(bstrEmailAddress, &bstrXMLRequest);
if (SUCCEEDED(hr))
{
ATOMICRELEASE(m_pXMLDocResponse);
ATOMICRELEASE(m_pXMLNodeAccount);
SysFreeString(m_bstrResponse);
m_bstrResponse = NULL;
_FreeProtocolList();
hr = _InternalDiscoverNow(bstrEmailAddress, (ADDN_DEFAULT | ADDN_CONFIGURE_EMAIL_FALLBACK | ADDN_FILTER_EMAIL), bstrXMLRequest, &m_pXMLDocResponse);
if (SUCCEEDED(hr) && !m_hwndAsync) // If we aren't async, parse now.
{
hr = _ParseResponse();
if (SUCCEEDED(hr))
{
m_fDiscovered = true;
}
}
SysFreeString(bstrXMLRequest);
}
}
return hr;
}
HRESULT CMailAccountDiscovery::_AsyncParseResponse(BSTR bstrEmail)
{
return HrSysAllocString(bstrEmail, &m_bstrResponse);
}
HRESULT CMailAccountDiscovery::_AsyncPrep(void)
{
HRESULT hr = S_OK;
// Now that we are back on the main thread. See if we
// need to turn the XML response back into a real COM object
// for the user to read.
if (m_hwndAsync && !m_pXMLDocResponse) // Are we async? And have we not yet parsed the response
{
hr = XMLDOMFromBStr(m_bstrResponse, &m_pXMLDocResponse);
if (SUCCEEDED(hr))
{
hr = _ParseResponse();
if (SUCCEEDED(hr))
{
m_fDiscovered = true;
}
}
}
return hr;
}
HRESULT CMailAccountDiscovery::PurgeCache(void)
{
HRESULT hr = E_INVALIDARG;
// TODO:
_FreeProtocolList();
return hr;
}
//===========================
// *** IUnknown Interface ***
//===========================
//===========================
// *** Class Methods ***
//===========================
HRESULT CMailAccountDiscovery::QueryInterface(REFIID riid, void **ppvObj)
{
HRESULT hr = E_NOINTERFACE;
static const QITAB qit[] = {
QITABENT(CMailAccountDiscovery, IMailAutoDiscovery),
QITABENT(CMailAccountDiscovery, IDispatch),
{ 0 },
};
hr = QISearch(this, qit, riid, ppvObj);
if (FAILED(hr))
{
hr = CAccountDiscoveryBase::QueryInterface(riid, ppvObj);
}
return hr;
}
CMailAccountDiscovery::CMailAccountDiscovery() : CImpIDispatch(LIBID_AutoDiscovery, 1, 0, IID_IMailAutoDiscovery)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_pXMLDocResponse);
ASSERT(!m_pXMLNodeAccount);
ASSERT(!m_bstrUserDisplayName);
ASSERT(!m_bstrInfoURL);
ASSERT(!m_bstrResponse);
m_hdsaProtocols = DSA_Create(sizeof(PROTOCOL_ENTRY), 1);
m_fDiscovered = false;
}
CMailAccountDiscovery::~CMailAccountDiscovery()
{
ATOMICRELEASE(m_pXMLNodeAccount);
ATOMICRELEASE(m_pXMLDocResponse);
SysFreeString(m_bstrUserDisplayName);
SysFreeString(m_bstrInfoURL);
SysFreeString(m_bstrResponse);
_FreeProtocolList();
DSA_DeleteAllItems(m_hdsaProtocols);
m_hdsaProtocols = NULL;
DllRelease();
}
HRESULT CMailAccountDiscovery_CreateInstance(IN IUnknown * punkOuter, REFIID riid, void ** ppvObj)
{
HRESULT hr = CLASS_E_NOAGGREGATION;
if (NULL == punkOuter)
{
if (ppvObj)
{
CMailAccountDiscovery * pThis = new CMailAccountDiscovery();
if (pThis)
{
hr = pThis->QueryInterface(riid, ppvObj);
pThis->Release();
}
else
{
*ppvObj = NULL;
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_INVALIDARG;
}
}
return hr;
}
//===========================
// *** IAutoDiscoveryProvider Interface ***
//===========================
HRESULT CADProviders::get_length(OUT long * pnLength)
{
HRESULT hr = E_INVALIDARG;
if (pnLength && m_hdpa)
{
*pnLength = (long) DSA_GetItemCount(m_hdpa);
hr = S_OK;
}
return hr;
}
HRESULT CADProviders::get_item(IN VARIANT varIndex, OUT BSTR * pbstr)
{
HRESULT hr = E_INVALIDARG;
if (pbstr)
{
long nCount = 0;
get_length(&nCount);
*pbstr = NULL;
hr = E_FAIL;
// This is sortof gross, but if we are passed a pointer to another variant, simply
// update our copy here...
if (varIndex.vt == (VT_BYREF | VT_VARIANT) && varIndex.pvarVal)
varIndex = *(varIndex.pvarVal);
switch (varIndex.vt)
{
case VT_I2:
varIndex.lVal = (long)varIndex.iVal;
// And fall through...
case VT_I4:
if ((varIndex.lVal >= 0) && (varIndex.lVal < nCount) && (0 < DSA_GetItemCount(m_hdpa)))
{
if (m_hdpa)
{
LPCWSTR pszFilename = (LPWSTR) DPA_GetPtr(m_hdpa, varIndex.lVal);
if (pszFilename)
{
hr = HrSysAllocString(pszFilename, pbstr);
}
}
}
break;
case VT_BSTR:
hr = E_NOTIMPL;
break;
default:
hr = E_NOTIMPL;
}
}
return hr;
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CADProviders::AddRef()
{
m_cRef++;
return m_cRef;
}
ULONG CADProviders::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
HRESULT CADProviders::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CADProviders, IAutoDiscoveryProvider),
QITABENT(CADProviders, IDispatch),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
//===========================
// *** Class Methods ***
//===========================
CADProviders::CADProviders(IN HDPA hdpa, IN IUnknown * punkParent) : CImpIDispatch(LIBID_AutoDiscovery, 1, 0, IID_IAutoDiscoveryProvider), m_cRef(1)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_hdpa);
ASSERT(!m_punkParent);
m_hdpa = hdpa;
IUnknown_Set((IUnknown **)&m_punkParent, punkParent);
}
CADProviders::~CADProviders()
{
IUnknown_Set((IUnknown **)&m_punkParent, NULL);
DllRelease();
}
HRESULT CADProviders_CreateInstance(IN HDPA hdpa, IN IUnknown * punkParent, OUT IAutoDiscoveryProvider ** ppProvider)
{
HRESULT hr = CLASS_E_NOAGGREGATION;
if (ppProvider)
{
CADProviders * pThis = new CADProviders(hdpa, punkParent);
if (pThis)
{
hr = pThis->QueryInterface(IID_PPV_ARG(IAutoDiscoveryProvider, ppProvider));
pThis->Release();
}
else
{
*ppProvider = NULL;
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_INVALIDARG;
}
return hr;
}