638 lines
12 KiB
C++
638 lines
12 KiB
C++
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
//
|
||
|
// File: row.cpp
|
||
|
//
|
||
|
// Contents: Cert Server Database interface implementation
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cpp>
|
||
|
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <certdb.h>
|
||
|
#include "csdisp.h"
|
||
|
#include "column.h"
|
||
|
#include "attrib.h"
|
||
|
#include "ext.h"
|
||
|
#include "row.h"
|
||
|
#include "view.h"
|
||
|
|
||
|
|
||
|
#if DBG_CERTSRV
|
||
|
LONG g_cCertViewRow;
|
||
|
LONG g_cCertViewRowTotal;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define CB_TARGETBUFFERSIZE (128 * 1024) // remote buffer size target
|
||
|
#define CROW_VIEWCHUNKMIN 35
|
||
|
|
||
|
|
||
|
CEnumCERTVIEWROW::CEnumCERTVIEWROW()
|
||
|
{
|
||
|
DBGCODE(InterlockedIncrement(&g_cCertViewRow));
|
||
|
DBGCODE(InterlockedIncrement(&g_cCertViewRowTotal));
|
||
|
m_pvw = NULL;
|
||
|
m_arowCache = NULL;
|
||
|
m_prowCacheCurrent = NULL;
|
||
|
m_cRef = 1;
|
||
|
m_ieltMax = -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
CEnumCERTVIEWROW::~CEnumCERTVIEWROW()
|
||
|
{
|
||
|
DBGCODE(InterlockedDecrement(&g_cCertViewRow));
|
||
|
|
||
|
#if DBG_CERTSRV
|
||
|
if (m_cRef > 1)
|
||
|
{
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"%hs has %d instances left over\n",
|
||
|
"CEnumCERTVIEWROW",
|
||
|
m_cRef));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (NULL != m_arowCache)
|
||
|
{
|
||
|
CoTaskMemFree((VOID *) m_arowCache);
|
||
|
m_arowCache = NULL;
|
||
|
}
|
||
|
if (NULL != m_pvw)
|
||
|
{
|
||
|
m_pvw->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CEnumCERTVIEWROW::Open(
|
||
|
IN ICertView *pvw)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == pvw)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
hr = ((CCertView *) pvw)->GetTable(&m_cvrcTable);
|
||
|
_JumpIfError(hr, error, "GetTable");
|
||
|
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"CEnumCERTVIEWROW::Open(cvrcTable=%x)\n",
|
||
|
m_cvrcTable));
|
||
|
|
||
|
m_pvw = pvw;
|
||
|
m_pvw->AddRef();
|
||
|
m_fNoMoreData = FALSE;
|
||
|
m_cskip = 0;
|
||
|
m_ielt = 0;
|
||
|
m_ieltCacheNext = 1;
|
||
|
m_crowChunk = 0;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CEnumCERTVIEWROW::_FindCachedRow(
|
||
|
IN LONG ielt,
|
||
|
OUT CERTTRANSDBRESULTROW const **ppRow)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
CERTTRANSDBRESULTROW const *prow;
|
||
|
ULONG i;
|
||
|
|
||
|
CSASSERT(NULL != ppRow);
|
||
|
*ppRow = NULL;
|
||
|
|
||
|
// If the server threw in an extra CERTTRANSDBRESULTROW structure containing
|
||
|
// the maximum element count, save the maximum count for later use.
|
||
|
|
||
|
prow = m_arowCache;
|
||
|
if (NULL != prow && m_fNoMoreData)
|
||
|
{
|
||
|
for (i = 0; i < m_celtCache; i++)
|
||
|
{
|
||
|
prow = (CERTTRANSDBRESULTROW const *) Add2ConstPtr(prow, prow->cbrow);
|
||
|
}
|
||
|
if (&prow[1] <=
|
||
|
(CERTTRANSDBRESULTROW const *) Add2ConstPtr(m_arowCache, m_cbCache) &&
|
||
|
prow->rowid == ~prow->ccol)
|
||
|
{
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"_FindCachedRow: ieltMax = %d -> %d\n",
|
||
|
m_ieltMax,
|
||
|
prow->rowid));
|
||
|
CSASSERT(-1 == m_ieltMax || (LONG) prow->rowid == m_ieltMax);
|
||
|
m_ieltMax = prow->rowid;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
prow = m_arowCache;
|
||
|
if (NULL == prow || ielt < m_ieltCacheFirst || ielt >= m_ieltCacheNext)
|
||
|
{
|
||
|
hr = S_FALSE; // requested row is not in the cached rowset
|
||
|
goto error;
|
||
|
}
|
||
|
for (ielt -= m_ieltCacheFirst; 0 < ielt; ielt--)
|
||
|
{
|
||
|
prow = (CERTTRANSDBRESULTROW const *) Add2ConstPtr(prow, prow->cbrow);
|
||
|
}
|
||
|
*ppRow = prow;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::GetMaxIndex(
|
||
|
/* [out, retval] */ LONG *pIndex)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == pIndex)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
if (-1 == m_ieltMax)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
_JumpError(hr, error, "m_ieltMax not set");
|
||
|
}
|
||
|
*pIndex = m_ieltMax;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::GetMaxIndex"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::Next(
|
||
|
/* [out, retval] */ LONG *pIndex)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LONG ielt;
|
||
|
LONG ieltNext;
|
||
|
LONG ieltFirst;
|
||
|
LONG cbrowResultNominal;
|
||
|
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"Trace: hr = pRow->Next(&lNext);\t_PrintIfError(hr, \"Next\");\n"));
|
||
|
if (NULL == pIndex)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
*pIndex = -1;
|
||
|
m_prowCacheCurrent = NULL;
|
||
|
|
||
|
ielt = m_ielt + m_cskip + 1;
|
||
|
|
||
|
hr = _FindCachedRow(ielt, &m_prowCacheCurrent);
|
||
|
if (S_FALSE != hr)
|
||
|
{
|
||
|
_JumpIfError(hr, error, "_FindCachedRow");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (m_fNoMoreData)
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
_JumpError2(hr, error, "NoMoreData", S_FALSE);
|
||
|
}
|
||
|
if (NULL != m_arowCache)
|
||
|
{
|
||
|
CoTaskMemFree((VOID *) m_arowCache);
|
||
|
m_arowCache = NULL;
|
||
|
}
|
||
|
if (0 == m_crowChunk) // First call
|
||
|
{
|
||
|
hr = ((CCertView *) m_pvw)->SetViewColumns(&cbrowResultNominal);
|
||
|
_JumpIfError(hr, error, "SetViewColumns");
|
||
|
|
||
|
m_crowChunk = CB_TARGETBUFFERSIZE / cbrowResultNominal;
|
||
|
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"ViewRow::Next: cbrowNominal=%d crowChunk=%d\n",
|
||
|
cbrowResultNominal,
|
||
|
m_crowChunk));
|
||
|
|
||
|
if (CROW_VIEWCHUNKMIN > m_crowChunk)
|
||
|
{
|
||
|
m_crowChunk = CROW_VIEWCHUNKMIN;
|
||
|
}
|
||
|
}
|
||
|
hr = ((CCertView *) m_pvw)->EnumView(
|
||
|
ielt - m_ieltCacheNext,
|
||
|
m_crowChunk,
|
||
|
&m_celtCache,
|
||
|
&m_ieltCacheNext,
|
||
|
&m_cbCache,
|
||
|
&m_arowCache);
|
||
|
if (S_FALSE == hr)
|
||
|
{
|
||
|
m_fNoMoreData = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_JumpIfError(hr, error, "EnumView");
|
||
|
}
|
||
|
m_ieltCacheFirst = m_ieltCacheNext - m_celtCache;
|
||
|
|
||
|
// workaround for bug 339811 causes this to fail
|
||
|
//CSASSERT(ielt == m_ieltCacheFirst);
|
||
|
|
||
|
hr = _FindCachedRow(ielt, &m_prowCacheCurrent);
|
||
|
_JumpIfError2(hr, error, "_FindCachedRow", S_FALSE);
|
||
|
}
|
||
|
m_cskip = 0;
|
||
|
m_ielt = ielt;
|
||
|
|
||
|
*pIndex = m_ielt;
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"ViewRow::Next: cskip=%d, ccache=%u:%u-%u, ielt=%u, ieltMax=%d, RowId=%u\n",
|
||
|
m_cskip,
|
||
|
m_celtCache,
|
||
|
m_ieltCacheFirst,
|
||
|
m_ieltCacheNext,
|
||
|
m_ielt,
|
||
|
m_ieltMax,
|
||
|
m_prowCacheCurrent->rowid));
|
||
|
|
||
|
error:
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"ViewRow::Next: cskip=%d, ccache=%u:%u-%u, ielt=%u, ieltMax=%d, *pIndex=%d, hr=%x\n",
|
||
|
m_cskip,
|
||
|
m_celtCache,
|
||
|
m_ieltCacheFirst,
|
||
|
m_ieltCacheNext,
|
||
|
m_ielt,
|
||
|
m_ieltMax,
|
||
|
NULL != pIndex? *pIndex : -1,
|
||
|
hr));
|
||
|
}
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::Next"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::EnumCertViewColumn(
|
||
|
/* [out] */ IEnumCERTVIEWCOLUMN **ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IEnumCERTVIEWCOLUMN *penum = NULL;
|
||
|
|
||
|
if (NULL == ppenum)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
*ppenum = NULL;
|
||
|
if (NULL == m_prowCacheCurrent)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
_JumpError(hr, error, "NULL m_prowCacheCurrent");
|
||
|
}
|
||
|
|
||
|
penum = new CEnumCERTVIEWCOLUMN;
|
||
|
if (NULL == penum)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
_JumpError(hr, error, "new CEnumCERTVIEWCOLUMN");
|
||
|
}
|
||
|
|
||
|
hr = ((CEnumCERTVIEWCOLUMN *) penum)->Open(
|
||
|
CVRC_COLUMN_VALUE,
|
||
|
m_ielt,
|
||
|
m_pvw,
|
||
|
m_prowCacheCurrent);
|
||
|
_JumpIfError(hr, error, "Open");
|
||
|
|
||
|
*ppenum = penum;
|
||
|
penum = NULL;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
if (NULL != penum)
|
||
|
{
|
||
|
penum->Release();
|
||
|
}
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::EnumCertViewColumn"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::EnumCertViewAttribute(
|
||
|
/* [in] */ LONG Flags,
|
||
|
/* [out, retval] */ IEnumCERTVIEWATTRIBUTE **ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IEnumCERTVIEWATTRIBUTE *penum = NULL;
|
||
|
|
||
|
if (NULL == ppenum)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
*ppenum = NULL;
|
||
|
|
||
|
if (NULL == m_prowCacheCurrent)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
_JumpError(hr, error, "NULL m_prowCacheCurrent");
|
||
|
}
|
||
|
if (CVRC_TABLE_REQCERT != m_cvrcTable)
|
||
|
{
|
||
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
||
|
_JumpError(hr, error, "table has no attributes");
|
||
|
}
|
||
|
|
||
|
penum = new CEnumCERTVIEWATTRIBUTE;
|
||
|
if (NULL == penum)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
_JumpError(hr, error, "new CEnumCERTVIEWATTRIBUTE");
|
||
|
}
|
||
|
|
||
|
hr = ((CEnumCERTVIEWATTRIBUTE *) penum)->Open(
|
||
|
m_prowCacheCurrent->rowid,
|
||
|
Flags,
|
||
|
m_pvw);
|
||
|
_JumpIfError(hr, error, "Open");
|
||
|
|
||
|
*ppenum = penum;
|
||
|
penum = NULL;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
if (NULL != penum)
|
||
|
{
|
||
|
penum->Release();
|
||
|
}
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::EnumCertViewAttribute"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::EnumCertViewExtension(
|
||
|
/* [in] */ LONG Flags,
|
||
|
/* [out, retval] */ IEnumCERTVIEWEXTENSION **ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IEnumCERTVIEWEXTENSION *penum = NULL;
|
||
|
|
||
|
if (NULL == ppenum)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
*ppenum = NULL;
|
||
|
|
||
|
if (NULL == m_prowCacheCurrent)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
_JumpError(hr, error, "NULL m_prowCacheCurrent");
|
||
|
}
|
||
|
if (CVRC_TABLE_REQCERT != m_cvrcTable)
|
||
|
{
|
||
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
||
|
_JumpError(hr, error, "table has no extensions");
|
||
|
}
|
||
|
|
||
|
penum = new CEnumCERTVIEWEXTENSION;
|
||
|
if (NULL == penum)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
_JumpError(hr, error, "new CEnumCERTVIEWEXTENSION");
|
||
|
}
|
||
|
|
||
|
hr = ((CEnumCERTVIEWEXTENSION *) penum)->Open(
|
||
|
m_prowCacheCurrent->rowid,
|
||
|
Flags,
|
||
|
m_pvw);
|
||
|
_JumpIfError(hr, error, "Open");
|
||
|
|
||
|
*ppenum = penum;
|
||
|
penum = NULL;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
if (NULL != penum)
|
||
|
{
|
||
|
penum->Release();
|
||
|
}
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::EnumCertViewExtension"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::Skip(
|
||
|
/* [in] */ LONG celt)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LONG cskipnew;
|
||
|
|
||
|
cskipnew = m_cskip + celt;
|
||
|
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"Trace: hr = pRow->Skip(%d);\t_PrintIfError(hr, \"Skip(%d)\");\n",
|
||
|
celt,
|
||
|
celt));
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"ViewRow::Skip(%d) ielt=%d: %d --> %d, skip=%d --> %d\n",
|
||
|
celt,
|
||
|
m_ielt,
|
||
|
m_ielt + m_cskip,
|
||
|
m_ielt + cskipnew,
|
||
|
m_cskip,
|
||
|
cskipnew));
|
||
|
|
||
|
CSASSERT(0 <= m_ielt);
|
||
|
if (0 > celt)
|
||
|
{
|
||
|
if (-1 > m_ielt + cskipnew)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
_JumpError(hr, error, "Skip back to before start");
|
||
|
}
|
||
|
m_fNoMoreData = FALSE;
|
||
|
}
|
||
|
|
||
|
m_prowCacheCurrent = NULL;
|
||
|
m_cskip = cskipnew;
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::Skip"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::Reset(VOID)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Trailing // and no newline comment out Skip() call we trigger:
|
||
|
|
||
|
DBGPRINT((
|
||
|
DBG_SS_CERTVIEWI,
|
||
|
"Trace: hr = pRow->Reset();\t_PrintIfError(hr, \"Reset\");\n// "));
|
||
|
|
||
|
hr = Skip(-(m_ielt + m_cskip));
|
||
|
_JumpIfError(hr, error, "Skip");
|
||
|
|
||
|
error:
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::Reset"));
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::Clone(
|
||
|
/* [out] */ IEnumCERTVIEWROW **ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IEnumCERTVIEWROW *penum = NULL;
|
||
|
LONG ielt;
|
||
|
|
||
|
if (NULL == ppenum)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
hr = m_pvw->OpenView(&penum);
|
||
|
_JumpIfError(hr, error, "OpenView");
|
||
|
|
||
|
ielt = m_ielt + m_cskip;
|
||
|
if (-1 != ielt)
|
||
|
{
|
||
|
if (NULL == m_prowCacheCurrent)
|
||
|
{
|
||
|
hr = penum->Skip(ielt);
|
||
|
_JumpIfError(hr, error, "Skip");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LONG Index;
|
||
|
|
||
|
hr = penum->Skip(ielt - 1);
|
||
|
_JumpIfError(hr, error, "Skip");
|
||
|
|
||
|
hr = penum->Next(&Index);
|
||
|
_JumpIfError(hr, error, "Next");
|
||
|
|
||
|
CSASSERT(Index == ielt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
if (NULL != ppenum)
|
||
|
{
|
||
|
*ppenum = penum;
|
||
|
}
|
||
|
return(_SetErrorInfo(hr, L"CEnumCERTVIEWROW::Clone"));
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CEnumCERTVIEWROW::_SetErrorInfo(
|
||
|
IN HRESULT hrError,
|
||
|
IN WCHAR const *pwszDescription)
|
||
|
{
|
||
|
CSASSERT(FAILED(hrError) || S_OK == hrError || S_FALSE == hrError);
|
||
|
if (FAILED(hrError))
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = DispatchSetErrorInfo(
|
||
|
hrError,
|
||
|
pwszDescription,
|
||
|
wszCLASS_CERTVIEW L".CEnumCERTVIEWROW",
|
||
|
&IID_IEnumCERTVIEWROW);
|
||
|
CSASSERT(hr == hrError);
|
||
|
}
|
||
|
return(hrError);
|
||
|
}
|
||
|
|
||
|
|
||
|
// IUnknown implementation
|
||
|
STDMETHODIMP
|
||
|
CEnumCERTVIEWROW::QueryInterface(
|
||
|
const IID& iid,
|
||
|
void **ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == ppv)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
_JumpError(hr, error, "NULL parm");
|
||
|
}
|
||
|
if (iid == IID_IUnknown)
|
||
|
{
|
||
|
*ppv = static_cast<IEnumCERTVIEWROW *>(this);
|
||
|
}
|
||
|
else if (iid == IID_IDispatch)
|
||
|
{
|
||
|
*ppv = static_cast<IEnumCERTVIEWROW *>(this);
|
||
|
}
|
||
|
else if (iid == IID_IEnumCERTVIEWROW)
|
||
|
{
|
||
|
*ppv = static_cast<IEnumCERTVIEWROW *>(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
hr = E_NOINTERFACE;
|
||
|
_JumpError(hr, error, "IID");
|
||
|
}
|
||
|
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
|
||
|
hr = S_OK;
|
||
|
|
||
|
error:
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CEnumCERTVIEWROW::AddRef()
|
||
|
{
|
||
|
return(InterlockedIncrement(&m_cRef));
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE
|
||
|
CEnumCERTVIEWROW::Release()
|
||
|
{
|
||
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||
|
|
||
|
if (0 == cRef)
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
return(cRef);
|
||
|
}
|