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.
3558 lines
110 KiB
3558 lines
110 KiB
// This is a part of the Microsoft Management Console.
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Management Console and related
|
|
// electronic documentation provided with the interfaces.
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "genpage.h"
|
|
|
|
#include "chooser.h"
|
|
#include "cryptui.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include <htmlhelp.h>
|
|
|
|
#define __dwFILE__ __dwFILE_CERTMMC_CSNAPIN_CPP__
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
// approx convert chars->pixels
|
|
#define CHARS_TO_MMCCOLUMNWIDTH(__strlen__) ((int)(__strlen__ * 7))
|
|
|
|
|
|
|
|
enum ENUM_MMCBUTTONS
|
|
{
|
|
ENUM_BUTTON_STARTSVC=0,
|
|
ENUM_BUTTON_STOPSVC,
|
|
};
|
|
|
|
MY_MMCBUTTON SvrMgrToolbar1Buttons[] =
|
|
{
|
|
{
|
|
{ 0, IDC_STARTSERVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"", L"" },
|
|
IDS_TASKMENU_STARTSERVICE,
|
|
IDS_TASKMENU_STATUSBAR_STARTSERVICE,
|
|
},
|
|
|
|
{
|
|
{ 1, IDC_STOPSERVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"", L"" },
|
|
IDS_TASKMENU_STOPSERVICE,
|
|
IDS_TASKMENU_STATUSBAR_STOPSERVICE,
|
|
},
|
|
|
|
{
|
|
{ 0, 0, 0, 0, NULL, NULL },
|
|
IDS_EMPTY,
|
|
IDS_EMPTY,
|
|
}
|
|
};
|
|
|
|
// Array of view items to be inserted into the context menu.
|
|
// keep this enum in synch with viewItems[]
|
|
enum ENUM_VIEW_ITEMS
|
|
{
|
|
ENUM_VIEW_ALL=0,
|
|
ENUM_VIEW_FILTER,
|
|
ENUM_VIEW_SEPERATOR,
|
|
};
|
|
|
|
MY_CONTEXTMENUITEM viewResultItems[] =
|
|
{
|
|
{
|
|
{
|
|
L"", L"",
|
|
IDC_VIEW_ALLRECORDS, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
|
|
},
|
|
IDS_VIEWMENU_ALL_RECORDS,
|
|
IDS_VIEWMENU_STATUSBAR_ALL_RECORDS,
|
|
},
|
|
|
|
{
|
|
{
|
|
L"", L"",
|
|
IDC_VIEW_FILTER, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
|
|
},
|
|
IDS_VIEWMENU_FILTER,
|
|
IDS_VIEWMENU_STATUSBAR_FILTER,
|
|
},
|
|
|
|
// seperator
|
|
{
|
|
{
|
|
L"", L"",
|
|
0, CCM_INSERTIONPOINTID_PRIMARY_VIEW, MF_ENABLED, CCM_SPECIAL_SEPARATOR
|
|
},
|
|
IDS_EMPTY,
|
|
IDS_EMPTY,
|
|
},
|
|
|
|
{
|
|
{ NULL, NULL, 0, 0, 0 },
|
|
IDS_EMPTY,
|
|
IDS_EMPTY,
|
|
}
|
|
};
|
|
|
|
enum ENUM_TASK_SINGLESELITEMS
|
|
{
|
|
ENUM_TASK_SEPERATOR1=0,
|
|
ENUM_TASK_UNREVOKE,
|
|
};
|
|
|
|
TASKITEM taskResultItemsSingleSel[] =
|
|
{
|
|
// seperator
|
|
|
|
{ SERVERFUNC_CRL_PUBLICATION,
|
|
TRUE,
|
|
{
|
|
{
|
|
L"", L"",
|
|
0, CCM_INSERTIONPOINTID_PRIMARY_TASK, MF_ENABLED, CCM_SPECIAL_SEPARATOR
|
|
},
|
|
IDS_EMPTY,
|
|
IDS_EMPTY,
|
|
}
|
|
},
|
|
|
|
{ SERVERFUNC_CRL_PUBLICATION,
|
|
TRUE,
|
|
{
|
|
{
|
|
L"", L"",
|
|
IDC_UNREVOKE_CERT, CCM_INSERTIONPOINTID_PRIMARY_TASK, MF_ENABLED, 0
|
|
},
|
|
IDS_TASKMENU_UNREVOKECERT,
|
|
IDS_TASKMENU_STATUSBAR_UNREVOKECERT,
|
|
CA_ACCESS_OFFICER,
|
|
}
|
|
},
|
|
|
|
{ NONE,
|
|
FALSE,
|
|
{
|
|
{ NULL, NULL, 0, 0, 0 },
|
|
IDS_EMPTY,
|
|
IDS_EMPTY,
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// Extracts the coclass guid format from the data object
|
|
//
|
|
template <class TYPE>
|
|
TYPE* Extract(LPDATAOBJECT lpDataObject, unsigned int cf)
|
|
{
|
|
ASSERT(lpDataObject != NULL);
|
|
|
|
TYPE* p = NULL;
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC formatetc = { (CLIPFORMAT)cf, NULL,
|
|
DVASPECT_CONTENT, -1, TYMED_HGLOBAL
|
|
};
|
|
|
|
// Allocate memory for the stream
|
|
int len;
|
|
|
|
if (cf == CDataObject::m_cfSelectedCA_CommonName)
|
|
len = (MAX_PATH+1) * sizeof(TYPE);
|
|
else if (cf == CDataObject::m_cfSelectedCA_MachineName)
|
|
len = (MAX_COMPUTERNAME_LENGTH+1) * sizeof(TYPE);
|
|
else
|
|
len = sizeof(TYPE);
|
|
|
|
|
|
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);
|
|
|
|
// Get the workstation name from the data object
|
|
do
|
|
{
|
|
if (stgmedium.hGlobal == NULL)
|
|
break;
|
|
|
|
if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
|
|
break;
|
|
|
|
p = reinterpret_cast<TYPE*>(stgmedium.hGlobal);
|
|
|
|
if (p == NULL)
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
return p;
|
|
}
|
|
|
|
BOOL IsMMCMultiSelectDataObject(LPDATAOBJECT pDataObject)
|
|
{
|
|
if (pDataObject == NULL)
|
|
return FALSE;
|
|
|
|
FORMATETC fmt = {(CLIPFORMAT)CDataObject::m_cfIsMultiSel, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
return (pDataObject->QueryGetData(&fmt) == S_OK);
|
|
}
|
|
|
|
// rip real pDataObject out of SMMCDataObjects struct
|
|
HGLOBAL GetMMCMultiSelDataObject(LPDATAOBJECT pDataObject)
|
|
{
|
|
if (pDataObject == NULL)
|
|
return FALSE;
|
|
|
|
static unsigned int s_cf = 0;
|
|
if (s_cf == 0)
|
|
s_cf = RegisterClipboardFormatW(CCF_MULTI_SELECT_SNAPINS);
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (FAILED(pDataObject->GetData(&fmt, &stgmedium)))
|
|
return NULL;
|
|
|
|
return stgmedium.hGlobal;
|
|
}
|
|
|
|
// Data object extraction helpers
|
|
CLSID* ExtractClassID(LPDATAOBJECT lpDataObject)
|
|
{
|
|
return Extract<CLSID>(lpDataObject, CDataObject::m_cfCoClass);
|
|
}
|
|
|
|
HGLOBAL ExtractNodeID(LPDATAOBJECT lpDataObject)
|
|
{
|
|
if (lpDataObject == NULL)
|
|
return FALSE;
|
|
|
|
static unsigned int s_cf = 0;
|
|
if (s_cf == 0)
|
|
s_cf = RegisterClipboardFormatW(CCF_COLUMN_SET_ID);
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (FAILED(lpDataObject->GetData(&fmt, &stgmedium)))
|
|
return NULL;
|
|
|
|
return stgmedium.hGlobal;
|
|
}
|
|
|
|
GUID* ExtractNodeType(LPDATAOBJECT lpDataObject)
|
|
{
|
|
return Extract<GUID>(lpDataObject, CDataObject::m_cfNodeType);
|
|
}
|
|
|
|
INTERNAL* ExtractInternalFormat(LPDATAOBJECT lpDataObject)
|
|
{
|
|
HRESULT hr;
|
|
if (lpDataObject == NULL)
|
|
return NULL;
|
|
|
|
// see if this is a multisel object
|
|
HGLOBAL hMem = NULL;
|
|
SMMCDataObjects* pRealObjectStruct = NULL;
|
|
INTERNAL* pRet = NULL;
|
|
|
|
if (IsMMCMultiSelectDataObject(lpDataObject))
|
|
{
|
|
// multisel object: extract real SMMCDataObjects
|
|
hMem = GetMMCMultiSelDataObject(lpDataObject);
|
|
_JumpIfOutOfMemory(hr, Ret, hMem);
|
|
|
|
pRealObjectStruct = (SMMCDataObjects*)::GlobalLock(hMem);
|
|
_JumpIfOutOfMemory(hr, Ret, pRealObjectStruct);
|
|
|
|
// may be a number of data objs in here; find OURS
|
|
BOOL fFound = FALSE;
|
|
for (DWORD i=0; i<pRealObjectStruct->count; i++)
|
|
{
|
|
CLSID* pExtractedID = ExtractClassID(pRealObjectStruct->lpDataObject[i]);
|
|
if (NULL != pExtractedID)
|
|
{
|
|
if (IsEqualCLSID(CLSID_Snapin, *pExtractedID))
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Free resources
|
|
GlobalFree(reinterpret_cast<HANDLE>(pExtractedID));
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
goto Ret;
|
|
|
|
// data obj that matches our CLSID
|
|
lpDataObject = pRealObjectStruct->lpDataObject[i];
|
|
}
|
|
pRet = Extract<INTERNAL>(lpDataObject, CDataObject::m_cfInternal);
|
|
if (pRet == NULL)
|
|
{
|
|
hr = myHLastError();
|
|
_PrintIfError(hr, "Extract CDO::m_cfInternal returned NULL");
|
|
}
|
|
|
|
Ret:
|
|
// free hMem
|
|
if (NULL != hMem)
|
|
{
|
|
GlobalUnlock(hMem);
|
|
GlobalFree(hMem);
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
|
|
/*
|
|
// only for use by OnRefresh -- this is a worker fxn
|
|
void CSnapin::RefreshFolder(CFolder* pFolder)
|
|
{
|
|
MMC_COOKIE cookie = (MMC_COOKIE)pFolder;
|
|
|
|
if (pFolder != NULL) // not base folder
|
|
{
|
|
// HIDE, remove all items, remove header, SHOW
|
|
OnShow(cookie, FALSE, 0); // emulate HIDE
|
|
m_pResult->DeleteAllRsltItems(); // delete items from m_pResult
|
|
while(S_OK == m_pHeader->DeleteColumn(0)) {}; // remove all cols from header
|
|
|
|
OnShow(cookie, TRUE, 0); // emulate SHOW
|
|
}
|
|
return;
|
|
}
|
|
*/
|
|
|
|
CFolder* CSnapin::GetParentFolder(INTERNAL* pInternal)
|
|
{
|
|
CFolder* p;
|
|
|
|
if(m_bVirtualView)
|
|
p = GetVirtualFolder();
|
|
else
|
|
p = ::GetParentFolder(pInternal);
|
|
|
|
#if DBG
|
|
if (p != m_pCurrentlySelectedScopeFolder)
|
|
{
|
|
if (NULL == p)
|
|
DBGPRINT((DBG_SS_CERTMMC, "Parent derived NULL, current saved folder is <%ws>\n", m_pCurrentlySelectedScopeFolder->m_pszName));
|
|
else if (NULL == m_pCurrentlySelectedScopeFolder)
|
|
DBGPRINT((DBG_SS_CERTMMC, "Parent derived as <%ws>, current saved folder is NULL\n", p->m_pszName));
|
|
else
|
|
DBGPRINT((DBG_SS_CERTMMC, "Parent derived as <%ws>, current saved folder is <%ws>\n", p->m_pszName, m_pCurrentlySelectedScopeFolder->m_pszName));
|
|
}
|
|
#endif
|
|
|
|
return p;
|
|
}
|
|
|
|
// independent of scope/result type, will return parent folder
|
|
CFolder* GetParentFolder(INTERNAL* pInternal)
|
|
{
|
|
if (NULL == pInternal)
|
|
return NULL;
|
|
|
|
if (CCT_SCOPE == pInternal->m_type)
|
|
{
|
|
return reinterpret_cast<CFolder*>(pInternal->m_cookie);
|
|
}
|
|
else if (CCT_RESULT == pInternal->m_type)
|
|
{
|
|
RESULT_DATA* pData = reinterpret_cast<RESULT_DATA*>(pInternal->m_cookie);
|
|
ASSERT(pData != NULL);
|
|
if (pData != NULL)
|
|
return pData->pParentFolder;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
HRESULT _QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, DWORD dwViewID,
|
|
CComponentDataImpl* pImpl, LPDATAOBJECT* ppDataObject)
|
|
{
|
|
ASSERT(ppDataObject != NULL);
|
|
ASSERT(pImpl != NULL);
|
|
|
|
CComObject<CDataObject>* pObject;
|
|
|
|
CComObject<CDataObject>::CreateInstance(&pObject);
|
|
ASSERT(pObject != NULL);
|
|
if (pObject == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Save cookie and type for delayed rendering
|
|
pObject->SetType(type);
|
|
pObject->SetCookie(cookie);
|
|
pObject->SetViewID(dwViewID);
|
|
|
|
// tell dataobj who we are
|
|
pObject->SetComponentData(pImpl);
|
|
|
|
// Store the coclass with the data object
|
|
pObject->SetClsid(pImpl->GetCoClassID());
|
|
|
|
return pObject->QueryInterface(IID_IDataObject,
|
|
reinterpret_cast<void**>(ppDataObject));
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Return TRUE if we are enumerating our main folder
|
|
|
|
BOOL CSnapin::IsEnumerating(LPDATAOBJECT lpDataObject)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
ASSERT(lpDataObject);
|
|
GUID* nodeType = ExtractNodeType(lpDataObject);
|
|
|
|
if (NULL != nodeType)
|
|
{
|
|
// Is this my main node (static folder node type)
|
|
if (::IsEqualGUID(*nodeType, cNodeTypeMachineInstance))
|
|
bResult = TRUE;
|
|
|
|
// Free resources
|
|
::GlobalFree(reinterpret_cast<HANDLE>(nodeType));
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSnapin's IComponent implementation
|
|
|
|
STDMETHODIMP
|
|
CSnapin::GetResultViewType(
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR *, // ppViewType
|
|
LONG *pViewOptions)
|
|
{
|
|
m_bVirtualView = FALSE;
|
|
|
|
// custom view: check guid
|
|
|
|
if (NULL == cookie)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_NONE;
|
|
return S_FALSE;
|
|
}
|
|
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT | MMC_VIEW_OPTIONS_NOLISTVIEWS;
|
|
|
|
// if ISSUED_CERT then make virtual list
|
|
CFolder* pFolder = (CFolder*)cookie;
|
|
if ((SERVERFUNC_CRL_PUBLICATION == pFolder->GetType()) ||
|
|
(SERVERFUNC_ISSUED_CERTIFICATES == pFolder->GetType()) ||
|
|
(SERVERFUNC_PENDING_CERTIFICATES == pFolder->GetType()) ||
|
|
(SERVERFUNC_FAILED_CERTIFICATES == pFolder->GetType()) ||
|
|
(SERVERFUNC_ALIEN_CERTIFICATES == pFolder->GetType()) ||
|
|
(SERVERFUNC_ISSUED_CRLS == pFolder->GetType()) )
|
|
{
|
|
*pViewOptions |= MMC_VIEW_OPTIONS_OWNERDATALIST;
|
|
m_bVirtualView = TRUE;
|
|
}
|
|
|
|
// if list view
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Initialize(LPCONSOLE lpConsole)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ASSERT(lpConsole != NULL);
|
|
m_bInitializedC = true;
|
|
|
|
// Save the IConsole pointer
|
|
if (lpConsole == NULL)
|
|
return E_POINTER;
|
|
hr = lpConsole->QueryInterface(IID_IConsole2,
|
|
reinterpret_cast<void**>(&m_pConsole));
|
|
_JumpIfError(hr, Ret, "QI IID_IConsole2");
|
|
|
|
// QI for a IHeaderCtrl
|
|
hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
|
|
reinterpret_cast<void**>(&m_pHeader));
|
|
_JumpIfError(hr, Ret, "QI IID_IHeaderCtrl");
|
|
|
|
// Give the console the header control interface pointer
|
|
m_pConsole->SetHeader(m_pHeader);
|
|
|
|
m_pConsole->QueryInterface(IID_IResultData,
|
|
reinterpret_cast<void**>(&m_pResult));
|
|
_JumpIfError(hr, Ret, "QI IID_IResultData");
|
|
|
|
hr = m_pConsole->QueryResultImageList(&m_pImageResult);
|
|
_JumpIfError(hr, Ret, "QueryResultImageList");
|
|
|
|
hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
|
|
_JumpIfError(hr, Ret, "QueryConsoleVerb");
|
|
|
|
hr = m_pConsole->QueryInterface(IID_IColumnData,
|
|
reinterpret_cast<void**>(&m_pViewData));
|
|
_JumpIfError(hr, Ret, "QI IID_IViewData");
|
|
|
|
Ret:
|
|
return hr;
|
|
}
|
|
|
|
// called by CompDataImpl on creation
|
|
void CSnapin::SetIComponentData(CComponentDataImpl* pData)
|
|
{
|
|
ASSERT(pData);
|
|
ASSERT(m_pComponentData == NULL);
|
|
LPUNKNOWN pUnk = pData->GetUnknown();
|
|
HRESULT hr;
|
|
|
|
hr = pUnk->QueryInterface(IID_IComponentData, reinterpret_cast<void**>(&m_pComponentData));
|
|
|
|
ASSERT(hr == S_OK);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CSnapin::Destroy(
|
|
MMC_COOKIE) // cookie
|
|
{
|
|
ASSERT(m_bInitializedC);
|
|
m_bDestroyedC = true;
|
|
|
|
// Release the interfaces that we QI'ed
|
|
if (m_pConsole != NULL)
|
|
{
|
|
// Tell the console to release the header control interface
|
|
m_pConsole->SetHeader(NULL);
|
|
SAFE_RELEASE(m_pHeader);
|
|
|
|
SAFE_RELEASE(m_pResult);
|
|
SAFE_RELEASE(m_pImageResult);
|
|
|
|
// Release the IConsole interface last
|
|
SAFE_RELEASE(m_pConsole);
|
|
SAFE_RELEASE(m_pComponentData); // QI'ed in CSnapin::SetIComponent
|
|
|
|
SAFE_RELEASE(m_pConsoleVerb);
|
|
SAFE_RELEASE(m_pViewData);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSnapin::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MMC_COOKIE cookie=0;
|
|
|
|
if (IS_SPECIAL_DATAOBJECT(lpDataObject))
|
|
{
|
|
if (event == MMCN_BTN_CLICK)
|
|
{
|
|
if (m_CustomViewID != VIEW_DEFAULT_LV)
|
|
{
|
|
switch (param)
|
|
{
|
|
case MMC_VERB_REFRESH:
|
|
|
|
OnRefresh(lpDataObject);
|
|
break;
|
|
|
|
case MMC_VERB_PROPERTIES:
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT((DBG_SS_CERTMMC, "MMCN_BTN_CLICK::param unknown"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (event)
|
|
{
|
|
case MMCN_VIEW_CHANGE:
|
|
case MMCN_REFRESH:
|
|
OnRefresh(lpDataObject);
|
|
break;
|
|
|
|
case MMCN_COLUMN_CLICK:
|
|
|
|
// On click, we need to fix sorting.
|
|
// Sorting info is usually retrieved from the view, but if a user column-clicks,
|
|
// IComponent::Sort is called before GetColumnSortData() is updated.
|
|
// In this case, we capture notification here and override GetColumnSortData() wrapper,
|
|
// and force a folder refresh.
|
|
|
|
// ask "IComponent::SortItems" if this is a valid column to sort on
|
|
hr = SortItems((int)arg, (DWORD)param, NULL);
|
|
|
|
// is sort allowed?
|
|
if (S_OK == hr)
|
|
{
|
|
m_ColSortOverride.colIdx = (int)arg;
|
|
m_ColSortOverride.dwOptions = (DWORD)param;
|
|
}
|
|
else
|
|
{
|
|
// don't allow sort
|
|
m_ColSortOverride.colIdx = -1;
|
|
}
|
|
|
|
m_ColSortOverride.fClickOverride = TRUE;
|
|
|
|
// notify view: sort was chosen
|
|
OnRefresh(lpDataObject);
|
|
|
|
m_ColSortOverride.fClickOverride = FALSE;
|
|
|
|
// bug 322746: since we're add/removing columns we should send Sort request
|
|
// m_pResult->Sort((int)arg, (DWORD)param, NULL);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_VIEW_CHANGE:
|
|
hr = OnUpdateView(lpDataObject, arg);
|
|
break;
|
|
case MMCN_DESELECT_ALL:
|
|
break;
|
|
case MMCN_COLUMN_CLICK:
|
|
break;
|
|
case MMCN_SNAPINHELP:
|
|
break;
|
|
case MMCN_HELP:
|
|
default:
|
|
{
|
|
INTERNAL* pInternal = NULL;
|
|
|
|
if (IsMMCMultiSelectDataObject(lpDataObject) == FALSE)
|
|
{
|
|
pInternal = ExtractInternalFormat(lpDataObject);
|
|
|
|
if (pInternal == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return S_OK;
|
|
}
|
|
|
|
if (pInternal)
|
|
cookie = pInternal->m_cookie;
|
|
}
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_ACTIVATE:
|
|
break;
|
|
|
|
case MMCN_CLICK:
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case MMCN_DBLCLICK:
|
|
|
|
// handle dblclick on Issued, CRL result items
|
|
if (pInternal && (CCT_RESULT == pInternal->m_type))
|
|
{
|
|
CFolder* pFolder = GetParentFolder(pInternal);
|
|
|
|
// if not base scope
|
|
ASSERT(pFolder != NULL);
|
|
if (pFolder == NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
// switch on folder type
|
|
switch(pFolder->m_type)
|
|
{
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
ASSERT(!IsMMCMultiSelectDataObject(lpDataObject));
|
|
if (!IsMMCMultiSelectDataObject(lpDataObject))
|
|
Command(IDC_VIEW_CERT_PROPERTIES, lpDataObject);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
hr = S_FALSE; // returning S_FALSE here means "Do the default verb"
|
|
break;
|
|
|
|
case MMCN_ADD_IMAGES:
|
|
OnAddImages(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_SHOW:
|
|
hr = OnShow(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_MINIMIZED:
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case MMCN_INITOCX:
|
|
break;
|
|
|
|
case MMCN_DESELECT_ALL:
|
|
case MMCN_SELECT:
|
|
HandleStandardVerbs((event == MMCN_DESELECT_ALL),
|
|
arg, lpDataObject);
|
|
break;
|
|
|
|
case MMCN_PASTE:
|
|
break;
|
|
|
|
case MMCN_DELETE:
|
|
break;
|
|
|
|
case MMCN_CONTEXTHELP:
|
|
hr = OnContextHelp(lpDataObject);
|
|
break;
|
|
|
|
case MMCN_REFRESH:
|
|
OnRefresh(lpDataObject);
|
|
break;
|
|
|
|
case MMCN_RENAME:
|
|
break;
|
|
|
|
case MMCN_COLUMNS_CHANGED:
|
|
{
|
|
MMC_VISIBLE_COLUMNS* psMMCCols = (MMC_VISIBLE_COLUMNS*)param;
|
|
if (psMMCCols == NULL)
|
|
break;
|
|
|
|
MMC_COLUMN_SET_DATA* pColSetData;
|
|
#if DEBUG_COLUMNS_CHANGED
|
|
|
|
hr = GetColumnSetData(cookie, &pColSetData);
|
|
if (hr == S_OK)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTMMC, "GetColumnSetData:\n"));
|
|
for (int i=0; i<pColSetData->nNumCols; i++)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTMMC,
|
|
L"pColData[%i]->nColIndex=%i (%hs)\n", i, pColSetData->pColData[i].nColIndex,
|
|
(pColSetData->pColData[i].dwFlags == HDI_HIDDEN) ? "hidden" : "shown"));
|
|
}
|
|
|
|
DBGPRINT((DBG_SS_CERTMMC, "VISIBLE_COLUMNS structure:\n"));
|
|
for (i=0; i<psMMCCols->nVisibleColumns; i++)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTMMC, L"Col %i is shown\n", psMMCCols->rgVisibleCols[i]));
|
|
}
|
|
|
|
if (pColSetData)
|
|
CoTaskMemFree(pColSetData);
|
|
}
|
|
#endif // DEBUG_COLUMNS_CHANGED
|
|
|
|
// On click, we need to fix column data
|
|
// This is analagous to the sort problem above -- we're given this notification
|
|
// before we can properly call GetColumnSetData(). Refresh does this, so we
|
|
// have to inform GetColumnSetData() of our true intent.
|
|
|
|
// fill in a fake COLUMN_SET_DATA, make it override
|
|
DWORD dwSize = sizeof(MMC_COLUMN_SET_DATA) + (psMMCCols->nVisibleColumns)*sizeof(MMC_COLUMN_DATA);
|
|
pColSetData = (MMC_COLUMN_SET_DATA* )LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, dwSize);
|
|
|
|
if (pColSetData)
|
|
{
|
|
pColSetData->cbSize = sizeof(MMC_COLUMN_SET_DATA);
|
|
pColSetData->nNumCols = psMMCCols->nVisibleColumns;
|
|
pColSetData->pColData = (MMC_COLUMN_DATA*) ((PBYTE)pColSetData + sizeof(MMC_COLUMN_SET_DATA)); // point just after struct
|
|
MMC_COLUMN_DATA* pEntry = pColSetData->pColData;
|
|
for (int i=0; i<pColSetData->nNumCols ; i++)
|
|
{
|
|
pEntry->nColIndex = psMMCCols->rgVisibleCols[i];
|
|
pEntry++;
|
|
}
|
|
m_ColSetOverride.pColSetData = pColSetData;
|
|
m_ColSetOverride.fClickOverride = TRUE;
|
|
}
|
|
|
|
// refresh to kick off requery: columns changed!
|
|
OnRefresh(lpDataObject);
|
|
|
|
// teardown
|
|
m_ColSetOverride.fClickOverride = FALSE;
|
|
if (m_ColSetOverride.pColSetData)
|
|
LocalFree(m_ColSetOverride.pColSetData);
|
|
}
|
|
break;
|
|
|
|
// Note - Future expansion of notify types possible
|
|
default:
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
FREE_DATA(pInternal);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CSnapin::OnUpdateView(
|
|
LPDATAOBJECT pDataObject,
|
|
LPARAM) // arg
|
|
{
|
|
OnRefresh(pDataObject);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void CSnapin::OnRefresh(LPDATAOBJECT pDataObject)
|
|
{
|
|
CWaitCursor cwait; // Could be long operation
|
|
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
ASSERT(pData != NULL);
|
|
|
|
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
|
|
|
|
// only allow scope refresh
|
|
if ((pInternal == NULL) || (pInternal->m_type == CCT_SCOPE))
|
|
{
|
|
if(pData)
|
|
{
|
|
// refresh toolbars
|
|
pData->m_pCertMachine->RefreshServiceStatus();
|
|
pData->UpdateScopeIcons();
|
|
}
|
|
SmartEnableServiceControlButtons();
|
|
}
|
|
/*
|
|
// Refresh the selected folder
|
|
CFolder* pFolder = GetParentFolder(pInternal);
|
|
RefreshFolder(pFolder);
|
|
*/
|
|
// Instead, re-select the current folder (acts like refresh)
|
|
// note side-effect: it causes race condition between redraw and
|
|
// MMCN_COLUMN_CLICKED database query -- MMC asks to draw cols that don't exist
|
|
if (m_pConsole && m_pCurrentlySelectedScopeFolder)
|
|
m_pConsole->SelectScopeItem(m_pCurrentlySelectedScopeFolder->m_ScopeItem.ID);
|
|
|
|
FREE_DATA(pInternal);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSnapin::OnContextHelp(
|
|
LPDATAOBJECT) // pdtobj
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CString cstrHelpFile;
|
|
IDisplayHelp* pDisplayHelp = NULL;
|
|
WCHAR szWindows[MAX_PATH];
|
|
szWindows[0] = L'\0';
|
|
|
|
hr = m_pConsole->QueryInterface (IID_IDisplayHelp, (void**)&pDisplayHelp);
|
|
_JumpIfError(hr, Ret, "QI IDisplayHelp");
|
|
|
|
if (0 == GetSystemWindowsDirectory(szWindows, MAX_PATH))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, Ret, "GetSystemWindowsDirectory");
|
|
}
|
|
|
|
cstrHelpFile = szWindows;
|
|
cstrHelpFile += HTMLHELP_COLLECTIONLINK_FILENAME;
|
|
cstrHelpFile += L"::/sag_cs_topnode.htm";
|
|
|
|
hr = pDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR)cstrHelpFile));
|
|
_JumpIfError(hr, Ret, "ShowTopic");
|
|
|
|
Ret:
|
|
if (pDisplayHelp)
|
|
pDisplayHelp->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSnapin::QueryMultiSelectDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT* ppDataObject)
|
|
{
|
|
const GUID* pguid;
|
|
|
|
ASSERT(ppDataObject != NULL);
|
|
if (ppDataObject == NULL)
|
|
return E_POINTER;
|
|
|
|
pguid = NULL;
|
|
if (m_bVirtualView)
|
|
{
|
|
ASSERT(GetVirtualFolder());
|
|
switch(GetVirtualFolder()->GetType())
|
|
{
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
pguid = &cNodeTypeCRLPublication;
|
|
break;
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
pguid = &cNodeTypeIssuedCerts;
|
|
break;
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
pguid = &cNodeTypePendingCerts;
|
|
break;
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
pguid = &cNodeTypeFailedCerts;
|
|
break;
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
pguid = &cNodeTypeAlienCerts;
|
|
break;
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
pguid = &cNodeTypeIssuedCRLs;
|
|
break;
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
CComObject<CDataObject>* pObject;
|
|
CComObject<CDataObject>::CreateInstance(&pObject);
|
|
ASSERT(pObject != NULL);
|
|
if (NULL == pObject)
|
|
return E_FAIL;
|
|
|
|
// Save cookie and type for delayed rendering
|
|
|
|
// fix type if unknown (is this valid?)
|
|
if (type == CCT_UNINITIALIZED)
|
|
type = CCT_RESULT;
|
|
|
|
pObject->SetType(type);
|
|
pObject->SetCookie(cookie);
|
|
pObject->SetMultiSelDobj();
|
|
|
|
CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
#ifdef _DEBUG
|
|
pObject->SetComponentData(pImpl);
|
|
#endif
|
|
|
|
// Store the coclass with the data object
|
|
pObject->SetClsid(pImpl->GetCoClassID());
|
|
|
|
// right now we know we have just 1 objtype
|
|
SMMCObjectTypes sGuidObjTypes;
|
|
sGuidObjTypes.count = 1;
|
|
CopyMemory(&sGuidObjTypes.guid[0], pguid, sizeof(GUID));
|
|
pObject->SetMultiSelData(&sGuidObjTypes, sizeof(sGuidObjTypes));
|
|
|
|
return pObject->QueryInterface(IID_IDataObject,
|
|
reinterpret_cast<void**>(ppDataObject));
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT* ppDataObject)
|
|
{
|
|
HRESULT hr;
|
|
if (cookie == MMC_MULTI_SELECT_COOKIE)
|
|
{
|
|
hr = QueryMultiSelectDataObject(cookie, type, ppDataObject);
|
|
}
|
|
else
|
|
{
|
|
// behavior: we may query for result or scope pane dataobjects
|
|
// Delegate it to the IComponentData
|
|
ASSERT(m_pComponentData != NULL);
|
|
CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
ASSERT(pImpl != NULL);
|
|
|
|
// Query for dataobj -- cookie is index
|
|
hr = _QueryDataObject(cookie, type, m_dwViewID, pImpl, ppDataObject);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSnapin's implementation specific members
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin);
|
|
|
|
CSnapin::CSnapin()
|
|
: m_hCertTypeList(NULL), m_bIsDirty(TRUE), m_bInitializedC(false), m_bDestroyedC(false)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin);
|
|
Construct();
|
|
}
|
|
|
|
CSnapin::~CSnapin()
|
|
{
|
|
#if DBG==1
|
|
ASSERT(dbg_cRef == 0);
|
|
#endif
|
|
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);
|
|
|
|
SAFE_RELEASE(m_pSvrMgrToolbar1);
|
|
|
|
if (m_pControlbar)
|
|
SAFE_RELEASE(m_pControlbar);
|
|
|
|
// Make sure the interfaces have been released
|
|
ASSERT(m_pConsole == NULL);
|
|
ASSERT(m_pHeader == NULL);
|
|
ASSERT(m_pSvrMgrToolbar1 == NULL);
|
|
|
|
ASSERT(!m_bInitializedC || m_bDestroyedC);
|
|
|
|
Construct();
|
|
|
|
if(m_hCertTypeList)
|
|
{
|
|
CACloseCertType(m_hCertTypeList);
|
|
m_hCertTypeList = NULL;
|
|
}
|
|
}
|
|
|
|
void CSnapin::Construct()
|
|
{
|
|
#if DBG==1
|
|
dbg_cRef = 0;
|
|
#endif
|
|
|
|
m_pConsole = NULL;
|
|
m_pHeader = NULL;
|
|
|
|
m_pResult = NULL;
|
|
m_pImageResult = NULL;
|
|
m_pComponentData = NULL;
|
|
|
|
m_bVirtualView = FALSE;
|
|
m_pCurrentlySelectedScopeFolder = NULL;
|
|
|
|
m_pControlbar = NULL;
|
|
|
|
m_pSvrMgrToolbar1 = NULL;
|
|
|
|
m_pConsoleVerb = NULL;
|
|
|
|
m_ColSortOverride.fClickOverride = FALSE;
|
|
m_ColSetOverride.fClickOverride = FALSE;
|
|
m_ColSetOverride.pColSetData = NULL;
|
|
|
|
m_CustomViewID = VIEW_DEFAULT_LV;
|
|
m_dwViewID = MAXDWORD;
|
|
|
|
m_cViewCalls = 0;
|
|
}
|
|
|
|
HRESULT CSnapin::SynchColumns(MMC_COOKIE cookie)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
CString* rgcstrCurSchemaHeading = NULL;
|
|
LONG* rglCurSchemaType = NULL;
|
|
BOOL* rgfCurSchemaIndexed = NULL;
|
|
DWORD cCurSchemaEntries = 0;
|
|
|
|
BOOL fSchemaChanged = FALSE;
|
|
BOOL fCertView;
|
|
|
|
CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
if ((pFolder == NULL) || (NULL == pData))
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, Ret, "pFolder or pData");
|
|
}
|
|
|
|
// if CCompDataImpl.m_rgLastKnownSchema is empty
|
|
// enumerate "Current Schema" and save in CCompDataImpl.m_rgLastKnownSchema
|
|
|
|
fCertView = SERVERFUNC_ISSUED_CRLS != pFolder->GetType();
|
|
// only resolve schema once per ccompdataimpl load
|
|
if (!pData->m_fSchemaWasResolved || // really, "SchemaWasUpdated"
|
|
pData->m_fCertView != fCertView)
|
|
{
|
|
pData->m_fSchemaWasResolved = TRUE;
|
|
pData->m_fCertView = fCertView;
|
|
|
|
// get new schema
|
|
hr = GetCurrentColumnSchema(
|
|
pFolder->m_pCertCA->m_strConfig,
|
|
pData->m_fCertView,
|
|
&rgcstrCurSchemaHeading,
|
|
&rglCurSchemaType,
|
|
&rgfCurSchemaIndexed,
|
|
(LONG*) &cCurSchemaEntries);
|
|
_JumpIfError(hr, Ret, "GetCurrentColumnSchema");
|
|
|
|
if (cCurSchemaEntries != pData->GetSchemaEntries())
|
|
{
|
|
fSchemaChanged = TRUE;
|
|
DBGPRINT((DBG_SS_CERTMMC, "Schema change detected: knew %i, now %i entries\n", pData->GetSchemaEntries(), cCurSchemaEntries));
|
|
}
|
|
else
|
|
{
|
|
// for each entry, compare headings
|
|
// report any diffc
|
|
for (DWORD iEntry=0; iEntry<cCurSchemaEntries; iEntry++)
|
|
{
|
|
LPCWSTR sz;
|
|
hr = pData->GetDBSchemaEntry(iEntry, &sz, NULL, NULL);
|
|
_JumpIfError(hr, Ret, "GetDbSchemaEntry");
|
|
|
|
if (!rgcstrCurSchemaHeading[iEntry].IsEqual(sz))
|
|
{
|
|
fSchemaChanged = TRUE;
|
|
DBGPRINT((DBG_SS_CERTMMC, "Schema change detected: entry %i changed\n", iEntry));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// boot old schema which only included strings.
|
|
// now we have types and indexes
|
|
DBGPRINT((DBG_SS_CERTMMC, "Updating saved schema\n"));
|
|
hr = pData->SetDBSchema(rgcstrCurSchemaHeading, rglCurSchemaType, rgfCurSchemaIndexed, cCurSchemaEntries);
|
|
_JumpIfError(hr, Ret, "SetDBSchema");
|
|
|
|
// these are now owned by the class
|
|
rgcstrCurSchemaHeading = NULL;
|
|
rglCurSchemaType = NULL;
|
|
rgfCurSchemaIndexed = NULL;
|
|
cCurSchemaEntries = 0;
|
|
|
|
if (fSchemaChanged)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTMMC, "Resetting folders\n"));
|
|
|
|
pData->ResetPersistedColumnInformation(); // create a new instance id (throws away all column width info)
|
|
|
|
// whack every loaded folder
|
|
POSITION pos = pData->m_scopeItemList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CFolder* pTmp = pData->m_scopeItemList.GetNext(pos);
|
|
ASSERT(pTmp);
|
|
if (pTmp == NULL)
|
|
hr = E_UNEXPECTED;
|
|
_JumpIfError(hr, Ret, "GetNext(pos) returns NULL");
|
|
|
|
// if we find a folder with the same CA
|
|
if (pTmp->GetCA() == pFolder->GetCA())
|
|
{
|
|
switch (pTmp->GetType())
|
|
{
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
// clear out cached data, it is stale
|
|
m_RowEnum.ResetColumnCount(pData->GetSchemaEntries());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} // end case
|
|
} // end if
|
|
} // end while folders
|
|
} // end if schema changed
|
|
}
|
|
|
|
Ret:
|
|
if (rgcstrCurSchemaHeading)
|
|
delete [] rgcstrCurSchemaHeading;
|
|
if (rglCurSchemaType)
|
|
delete [] rglCurSchemaType;
|
|
if (rgfCurSchemaIndexed)
|
|
delete [] rgfCurSchemaIndexed;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CSnapin::GetColumnSetData(MMC_COOKIE cookie, MMC_COLUMN_SET_DATA** ppColSetData)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (m_ColSetOverride.fClickOverride)
|
|
{
|
|
// give caller structure to free, but caller doesn't care that
|
|
// he just gets a reference to our COLUMN_DATA array...
|
|
|
|
*ppColSetData = (MMC_COLUMN_SET_DATA*)CoTaskMemAlloc(sizeof(MMC_COLUMN_SET_DATA));
|
|
if (NULL != *ppColSetData)
|
|
{
|
|
CopyMemory(*ppColSetData, m_ColSetOverride.pColSetData, sizeof(MMC_COLUMN_SET_DATA));
|
|
return S_OK;
|
|
}
|
|
// else fall through; worst case is "Err Invalid Index..." in UI
|
|
}
|
|
|
|
HGLOBAL hSNode2 = NULL;
|
|
SColumnSetID* pColID = NULL;
|
|
|
|
LPDATAOBJECT lpDataObject = NULL;
|
|
|
|
hr = _QueryDataObject(cookie, CCT_SCOPE, m_dwViewID,
|
|
reinterpret_cast<CComponentDataImpl*>(m_pComponentData), &lpDataObject);
|
|
_JumpIfError(hr, Ret, "_QueryDataObject");
|
|
|
|
hSNode2 = ExtractNodeID(lpDataObject);
|
|
_JumpIfOutOfMemory(hr, Ret, hSNode2);
|
|
|
|
pColID = (SColumnSetID*)GlobalLock(hSNode2);
|
|
_JumpIfOutOfMemory(hr, Ret, pColID);
|
|
|
|
hr = m_pViewData->GetColumnConfigData(pColID, ppColSetData);
|
|
_PrintIfError(hr, "GetColumnConfigData");
|
|
|
|
if (*ppColSetData == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
_JumpError(hr, Ret, "*ppColSetData NULL");
|
|
}
|
|
// register this allocation
|
|
myRegisterMemAlloc(*ppColSetData, -1, CSM_COTASKALLOC);
|
|
|
|
Ret:
|
|
if (hSNode2)
|
|
{
|
|
GlobalUnlock(hSNode2);
|
|
GlobalFree(hSNode2);
|
|
}
|
|
|
|
if (lpDataObject)
|
|
lpDataObject->Release();
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSnapin::GetColumnSortData(MMC_COOKIE cookie, int* piColSortIdx, BOOL* pfAscending)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (m_ColSortOverride.fClickOverride)
|
|
{
|
|
// remove sort
|
|
if (m_ColSortOverride.colIdx == -1)
|
|
return E_FAIL;
|
|
|
|
*piColSortIdx = m_ColSortOverride.colIdx;
|
|
*pfAscending = ((m_ColSortOverride.dwOptions & RSI_DESCENDING) == 0) ? TRUE : FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
HGLOBAL hSNode2 = NULL;
|
|
SColumnSetID* pColID = NULL;
|
|
MMC_SORT_SET_DATA* pSortSetData = NULL;
|
|
|
|
LPDATAOBJECT lpDataObject = NULL;
|
|
|
|
hr = _QueryDataObject(cookie, CCT_SCOPE, m_dwViewID,
|
|
reinterpret_cast<CComponentDataImpl*>(m_pComponentData), &lpDataObject);
|
|
_JumpIfError(hr, Ret, "_QueryDataObject");
|
|
|
|
hSNode2 = ExtractNodeID(lpDataObject);
|
|
_JumpIfOutOfMemory(hr, Ret, hSNode2);
|
|
|
|
pColID = (SColumnSetID*)GlobalLock(hSNode2);
|
|
_JumpIfOutOfMemory(hr, Ret, pColID);
|
|
|
|
hr = m_pViewData->GetColumnSortData(pColID, &pSortSetData);
|
|
_JumpIfError(hr, Ret, "GetColumnSortData");
|
|
|
|
if (NULL == pSortSetData)
|
|
{
|
|
hr = E_FAIL;
|
|
_JumpError(hr, Ret, "pSortSetData NULL");
|
|
}
|
|
myRegisterMemAlloc(pSortSetData, -1, CSM_COTASKALLOC);
|
|
|
|
ASSERT(pSortSetData->nNumItems <= 1);
|
|
if (pSortSetData->nNumItems == 0)
|
|
{
|
|
hr = E_FAIL;
|
|
_JumpError(hr, Ret, "pSortSetData no sort");
|
|
}
|
|
|
|
*piColSortIdx = pSortSetData->pSortData[0].nColIndex;
|
|
*pfAscending = ((pSortSetData->pSortData[0].dwSortOptions & RSI_DESCENDING) == 0) ? TRUE : FALSE;
|
|
|
|
Ret:
|
|
if (hSNode2)
|
|
{
|
|
GlobalUnlock(hSNode2);
|
|
GlobalFree(hSNode2);
|
|
}
|
|
|
|
if (lpDataObject)
|
|
lpDataObject->Release();
|
|
|
|
if (pSortSetData)
|
|
CoTaskMemFree(pSortSetData);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSnapin::InsertAllColumns(MMC_COOKIE cookie, CertViewRowEnum* pCertViewRowEnum)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
|
|
IEnumCERTVIEWCOLUMN* pColEnum = NULL;
|
|
|
|
BOOL fColumnDataBad = FALSE;
|
|
LONG iResultColCount;
|
|
int iCache, i;
|
|
BSTR bstrColumn = NULL;
|
|
|
|
MMC_COLUMN_SET_DATA* pColConfigData = NULL;
|
|
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
if (NULL == pData)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, Ret, "pData NULL");
|
|
}
|
|
|
|
ICertView* pICertView; // this is const, don't free
|
|
hr = pCertViewRowEnum->GetView(pFolder->GetCA(), &pICertView);
|
|
_JumpIfError(hr, Ret, "GetView");
|
|
|
|
// always reset our column cache map
|
|
hr = m_RowEnum.ResetColumnCount(pData->m_cLastKnownSchema);
|
|
_JumpIfError(hr, Ret, "ResetColumnCount");
|
|
|
|
// attempt to get column set data
|
|
hr = GetColumnSetData(cookie, &pColConfigData);
|
|
_PrintIfError2(hr, "GetColumnConfigData", E_FAIL);
|
|
|
|
|
|
// call SetColumnCacheInfo to update final Result Indexes
|
|
if ((hr != S_OK) || // given 1) canned view or
|
|
(pData->m_cLastKnownSchema != (unsigned int)pColConfigData->nNumCols) )
|
|
// 2) pColConfigData doesn't agree with schema
|
|
{
|
|
if (hr == S_OK)
|
|
fColumnDataBad = TRUE;
|
|
|
|
// get col enumerator
|
|
hr = pICertView->EnumCertViewColumn(TRUE, &pColEnum);
|
|
_JumpIfError(hr, Ret, "EnumCertViewColumn");
|
|
|
|
// get # of result cols
|
|
hr = pICertView->GetColumnCount(TRUE, &iResultColCount);
|
|
_JumpIfError(hr, Ret, "GetColumnCount");
|
|
|
|
// this doesn't agree with schema -- throw it away
|
|
if (pColConfigData)
|
|
{
|
|
CoTaskMemFree(pColConfigData);
|
|
pColConfigData = NULL;
|
|
}
|
|
ASSERT(pColConfigData == NULL);
|
|
|
|
// rig up a column set data as if we got it from mmc
|
|
pColConfigData = (MMC_COLUMN_SET_DATA*)CoTaskMemAlloc(sizeof(MMC_COLUMN_SET_DATA) + (sizeof(MMC_COLUMN_DATA)*pData->m_cLastKnownSchema));
|
|
_JumpIfOutOfMemory(hr, Ret, pColConfigData);
|
|
|
|
ZeroMemory(pColConfigData, sizeof(MMC_COLUMN_SET_DATA) + (sizeof(MMC_COLUMN_DATA)*pData->m_cLastKnownSchema));
|
|
pColConfigData->pColData = (MMC_COLUMN_DATA*) (((BYTE*)pColConfigData) + sizeof(MMC_COLUMN_SET_DATA)); // points to just after our struct
|
|
pColConfigData->cbSize = sizeof(MMC_COLUMN_SET_DATA);
|
|
pColConfigData->nNumCols = pData->m_cLastKnownSchema;
|
|
|
|
for (i=0; i<(int)pData->m_cLastKnownSchema; i++)
|
|
{
|
|
pColConfigData->pColData[i].nColIndex = i;
|
|
pColConfigData->pColData[i].dwFlags = HDI_HIDDEN;
|
|
}
|
|
|
|
for (i=0; i< iResultColCount; i++)
|
|
{
|
|
hr = pColEnum->Next((LONG*)&iCache);
|
|
_JumpIfError(hr, Ret, "Next");
|
|
|
|
hr = pColEnum->GetName(&bstrColumn);
|
|
_JumpIfError(hr, Ret, "GetName");
|
|
|
|
iCache = pData->FindColIdx(bstrColumn);
|
|
_JumpIfError(hr, Ret, "FindColIdx");
|
|
|
|
SysFreeString(bstrColumn);
|
|
bstrColumn = NULL;
|
|
|
|
// rig up column set data as if we got it from mmc
|
|
pColConfigData->pColData[iCache].dwFlags = (DWORD) AUTO_WIDTH;
|
|
|
|
hr = m_RowEnum.SetColumnCacheInfo(iCache, i);
|
|
_JumpIfError(hr, Ret, "SetColumnCacheInfo");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// get # of cols
|
|
iResultColCount = m_RowEnum.GetColumnCount();
|
|
|
|
// set col cache correctly
|
|
int iResultIdx = 0;
|
|
for (i=0; i< iResultColCount; i++)
|
|
{
|
|
BOOL fShown;
|
|
hr = IsColumnShown(pColConfigData, i, &fShown);
|
|
_JumpIfError(hr, Ret, "IsColumnShown");
|
|
|
|
// update idxViewCol
|
|
if (fShown)
|
|
{
|
|
hr = m_RowEnum.SetColumnCacheInfo(pColConfigData->pColData[i].nColIndex, iResultIdx);
|
|
_JumpIfError(hr, Ret, "SetColumnCacheInfo");
|
|
|
|
iResultIdx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = DoInsertAllColumns(pColConfigData);
|
|
_JumpIfError(hr, Ret, "DoInsertAllColumns");
|
|
|
|
Ret:
|
|
if (pColEnum)
|
|
pColEnum->Release();
|
|
|
|
if (bstrColumn)
|
|
SysFreeString(bstrColumn);
|
|
|
|
if(pColConfigData)
|
|
CoTaskMemFree(pColConfigData);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSnapin::DoInsertAllColumns(MMC_COLUMN_SET_DATA* pCols)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
int i;
|
|
|
|
if ((pCols == NULL) || (pData == NULL))
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, Ret, "pCols or pData");
|
|
}
|
|
|
|
for (i=0; i<pCols->nNumCols; i++)
|
|
{
|
|
LPCWSTR pszLocal, pszUnlocal;
|
|
BOOL fShown;
|
|
|
|
hr = IsColumnShown(pCols, i, &fShown);
|
|
_JumpIfError(hr, Ret, "IsColumnShown");
|
|
|
|
hr = pData->GetDBSchemaEntry(i, &pszUnlocal, NULL, NULL);
|
|
_JumpIfError(hr, Ret, "GetDBSchemaEntry");
|
|
|
|
// returns pointer to static data; don't bother to free
|
|
hr = myGetColumnDisplayName(
|
|
pszUnlocal,
|
|
&pszLocal);
|
|
_PrintIfError(hr, "myGetColumnDisplayName");
|
|
|
|
// if localized version not found, slap with raw name
|
|
if (pszLocal == NULL)
|
|
pszLocal = pszUnlocal;
|
|
|
|
m_pHeader->InsertColumn(i, pszLocal, LVCFMT_LEFT, fShown ? AUTO_WIDTH : HIDE_COLUMN);
|
|
}
|
|
|
|
Ret:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CSnapin::InitializeHeaders(MMC_COOKIE cookie)
|
|
{
|
|
ASSERT(m_pHeader);
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fInsertedHeaders=FALSE;
|
|
|
|
USES_CONVERSION;
|
|
|
|
CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
|
|
MMC_COLUMN_SET_DATA* pColSetData = NULL;
|
|
|
|
// Put the correct headers depending on the cookie
|
|
if (pFolder == NULL)
|
|
{
|
|
// base scope
|
|
m_pHeader->InsertColumn(0, W2COLE(g_pResources->m_ColumnHead_Name), LVCFMT_LEFT, 180); // Name
|
|
m_pHeader->InsertColumn(1, W2COLE(g_pResources->m_ColumnHead_Description), LVCFMT_LEFT, 180); // Description
|
|
fInsertedHeaders = TRUE;
|
|
}
|
|
else
|
|
{
|
|
switch (pFolder->m_type)
|
|
{
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_CRL_PUBLICATION: // or server functions
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
{
|
|
ICertView* pICertView; // this is const, don't free
|
|
BOOL fCertView;
|
|
|
|
m_dwViewErrorMsg = S_OK; // assume everything OK when initializing view
|
|
|
|
// although we don't allow unsetting this mode,
|
|
// we may inherit it from another snapin. Force report mode.
|
|
hr = m_pResult->SetViewMode(MMCLV_VIEWSTYLE_REPORT);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// force reload of view (otherwise: multiple restriction error)
|
|
ResetKnowResultRows();
|
|
m_RowEnum.ClearCachedCertView();
|
|
m_RowEnum.InvalidateCachedRowEnum();
|
|
fCertView = SERVERFUNC_ISSUED_CRLS != pFolder->m_type;
|
|
hr = m_RowEnum.GetView(pFolder->GetCA(), &pICertView);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
int iSortOrder = CVR_SORT_NONE;
|
|
int idxSortCol = -1;
|
|
|
|
ASSERT(pICertView != NULL);
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
|
|
if (!fCertView)
|
|
{
|
|
hr = ((ICertView2 *) pICertView)->SetTable(CVRC_TABLE_CRL);
|
|
_PrintIfError(hr, "SetTable");
|
|
}
|
|
{
|
|
BOOL fAscending;
|
|
hr = GetColumnSortData(cookie, &idxSortCol, &fAscending);
|
|
_PrintIfError2(hr, "GetColumnSortData", E_FAIL);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (fAscending)
|
|
iSortOrder = CVR_SORT_ASCEND;
|
|
else
|
|
iSortOrder = CVR_SORT_DESCEND;
|
|
|
|
}
|
|
}
|
|
|
|
// first restriction is always sort request
|
|
if (iSortOrder != CVR_SORT_NONE)
|
|
{
|
|
ASSERT( (iSortOrder == CVR_SORT_ASCEND) ||
|
|
(iSortOrder == CVR_SORT_DESCEND));
|
|
|
|
var.vt = VT_EMPTY;
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pICertView->SetRestriction(
|
|
idxSortCol, // ColumnIndex
|
|
CVR_SEEK_NONE, // SeekOperator
|
|
iSortOrder, // SortOrder
|
|
&var); // pvarValue
|
|
}
|
|
VariantClear(&var);
|
|
}
|
|
|
|
|
|
|
|
// set restriction on rows to view
|
|
if (m_RowEnum.FAreQueryRestrictionsActive(fCertView) &&
|
|
(m_RowEnum.GetQueryRestrictions(fCertView) != NULL))
|
|
{
|
|
PQUERY_RESTRICTION pCurRestrict = m_RowEnum.GetQueryRestrictions(fCertView);
|
|
while (pCurRestrict)
|
|
{
|
|
LONG idxCol;
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(pCurRestrict->szField), &idxCol);
|
|
if (hr == S_OK)
|
|
{
|
|
// set restriction if column found
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
pCurRestrict->iOperation, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&pCurRestrict->varValue); // Value
|
|
}
|
|
|
|
// don't VarClear here!
|
|
pCurRestrict = pCurRestrict->pNext;
|
|
}
|
|
}
|
|
|
|
// set query restrictions
|
|
if (SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)
|
|
{
|
|
// build special Revoked view
|
|
var.lVal = DB_DISP_REVOKED;
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_EQ, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else if (SERVERFUNC_ISSUED_CERTIFICATES == pFolder->m_type)
|
|
{
|
|
var.lVal = DB_DISP_ISSUED;
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_EQ, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else if (SERVERFUNC_PENDING_CERTIFICATES == pFolder->m_type)
|
|
{
|
|
var.lVal = DB_DISP_PENDING; //DB_DISP_QUEUE_MAX; // don't include active
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_EQ, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else if (SERVERFUNC_FAILED_CERTIFICATES == pFolder->m_type)
|
|
{
|
|
var.lVal = DB_DISP_LOG_FAILED_MIN;
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_GE, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else if (SERVERFUNC_ALIEN_CERTIFICATES == pFolder->m_type)
|
|
{
|
|
var.lVal = DB_DISP_FOREIGN;
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPREQUESTDOT wszPROPREQUESTDISPOSITION), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_EQ, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else if (SERVERFUNC_ISSUED_CRLS == pFolder->m_type)
|
|
{
|
|
var.lVal = 0;
|
|
var.vt = VT_I4;
|
|
LONG idxCol;
|
|
|
|
hr = pICertView->GetColumnIndex(FALSE, _bstr_t(wszPROPCRLROWID), &idxCol);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetRestriction(
|
|
idxCol, // Request Disposition's ColumnIndex
|
|
CVR_SEEK_GE, // SeekOperator
|
|
CVR_SORT_NONE, // SortOrder
|
|
&var); // pvarValue
|
|
|
|
VariantClear(&var);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE); // do we ever get here??
|
|
break;
|
|
}
|
|
|
|
// RESOLVE schema changes here
|
|
hr = SynchColumns(cookie);
|
|
_PrintIfError(hr, "SynchColumns");
|
|
|
|
hr = GetColumnSetData(cookie, &pColSetData);
|
|
if ((hr != S_OK) || (pColSetData == NULL))
|
|
{
|
|
LONG lViewType;
|
|
|
|
// problem or no column set data? Revert to the default canned view
|
|
if (SERVERFUNC_PENDING_CERTIFICATES == pFolder->m_type)
|
|
lViewType = CV_COLUMN_QUEUE_DEFAULT;
|
|
else if (SERVERFUNC_FAILED_CERTIFICATES == pFolder->m_type)
|
|
lViewType = CV_COLUMN_LOG_FAILED_DEFAULT;
|
|
else if (SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)
|
|
lViewType = pFolder->GetCA()->m_pParentMachine->FIsWhistlerMachine() ? CV_COLUMN_LOG_REVOKED_DEFAULT : CV_COLUMN_LOG_DEFAULT; // w2k doesn't understand revoked view
|
|
else if (SERVERFUNC_ALIEN_CERTIFICATES == pFolder->m_type)
|
|
lViewType = CV_COLUMN_LOG_DEFAULT;
|
|
else if (SERVERFUNC_ISSUED_CRLS == pFolder->m_type)
|
|
lViewType = CV_COLUMN_CRL_DEFAULT;
|
|
else
|
|
lViewType = CV_COLUMN_LOG_DEFAULT;
|
|
|
|
hr = pICertView->SetResultColumnCount(lViewType);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// manual view
|
|
ULONG lColCount;
|
|
|
|
hr = CountShownColumns(pColSetData, &lColCount);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pICertView->SetResultColumnCount(lColCount);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// for all non-hidden columns, add to Query
|
|
for (lColCount=0; lColCount<(ULONG)pColSetData->nNumCols; lColCount++)
|
|
{
|
|
BOOL fShown;
|
|
hr = IsColumnShown(pColSetData, lColCount, &fShown);
|
|
if ((hr != S_OK) || (!fShown))
|
|
continue;
|
|
|
|
hr = pICertView->SetResultColumn(pColSetData->pColData[lColCount].nColIndex);
|
|
if (hr != S_OK)
|
|
break;
|
|
}
|
|
}
|
|
// Open the view
|
|
IEnumCERTVIEWROW* pRowEnum; // don't free
|
|
hr = m_RowEnum.GetRowEnum(pFolder->GetCA(), &pRowEnum);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
|
|
hr = InsertAllColumns(cookie, &m_RowEnum);
|
|
_PrintIfError(hr, "InsertAllColumns");
|
|
|
|
if (hr == S_OK)
|
|
fInsertedHeaders = TRUE;
|
|
|
|
|
|
// set description bar text
|
|
{
|
|
CString cstrStatusBar;
|
|
BOOL fFiltered = FALSE;
|
|
|
|
if (m_RowEnum.FAreQueryRestrictionsActive(fCertView) &&
|
|
(m_RowEnum.GetQueryRestrictions(fCertView) != NULL))
|
|
{
|
|
cstrStatusBar = g_pResources->m_szFilterApplied;
|
|
fFiltered = TRUE;
|
|
}
|
|
|
|
if (iSortOrder != CVR_SORT_NONE)
|
|
{
|
|
LPCWSTR pszTemplate = NULL;
|
|
if (iSortOrder == CVR_SORT_ASCEND)
|
|
pszTemplate = (LPCWSTR)g_pResources->m_szSortedAscendingTemplate;
|
|
|
|
if (iSortOrder == CVR_SORT_DESCEND)
|
|
pszTemplate = (LPCWSTR)g_pResources->m_szSortedDescendingTemplate;
|
|
|
|
if (pszTemplate)
|
|
{
|
|
// localize
|
|
LPCWSTR szUnlocalizedCol;
|
|
LPCWSTR szLocalizedCol;
|
|
|
|
hr = dynamic_cast<CComponentDataImpl*>(m_pComponentData)->GetDBSchemaEntry(idxSortCol, &szUnlocalizedCol, NULL, NULL);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = myGetColumnDisplayName(
|
|
szUnlocalizedCol,
|
|
&szLocalizedCol);
|
|
if ((S_OK == hr) && (NULL != szLocalizedCol))
|
|
{
|
|
WCHAR rgszSortText[MAX_PATH+1];
|
|
ASSERT((MAX_PATH*sizeof(WCHAR)) > (WSZ_BYTECOUNT(pszTemplate) + WSZ_BYTECOUNT(szLocalizedCol)));
|
|
wsprintf(rgszSortText, pszTemplate, szLocalizedCol);
|
|
|
|
if (fFiltered)
|
|
cstrStatusBar += L"; ";
|
|
cstrStatusBar += rgszSortText;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Progress: cstrStatusBar += L"|%69";
|
|
//m_pResult->SetDescBarText((LPWSTR)(LPCWSTR)cstrStatusBar);
|
|
m_pConsole->SetStatusText((LPWSTR)(LPCWSTR)cstrStatusBar);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SERVER_INSTANCE: // any issuing server instance
|
|
m_pHeader->InsertColumn(0, W2COLE(g_pResources->m_ColumnHead_Name), LVCFMT_LEFT, 260); // Name
|
|
fInsertedHeaders = TRUE;
|
|
break;
|
|
default:
|
|
// other scopes
|
|
m_pHeader->InsertColumn(0, W2COLE(g_pResources->m_ColumnHead_Name), LVCFMT_LEFT, 180); // Name
|
|
m_pHeader->InsertColumn(1, W2COLE(g_pResources->m_ColumnHead_Size), LVCFMT_LEFT, 90); // Size
|
|
m_pHeader->InsertColumn(2, W2COLE(g_pResources->m_ColumnHead_Type), LVCFMT_LEFT, 160); // Type
|
|
fInsertedHeaders = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fInsertedHeaders)
|
|
{
|
|
// insert error msg
|
|
CString cstrViewErrorMsg, cstrStatusText;
|
|
|
|
if ((pFolder != NULL ) && (!pFolder->GetCA()->m_pParentMachine->IsCertSvrServiceRunning()))
|
|
{
|
|
// handle server stopped msg
|
|
cstrViewErrorMsg = g_pResources->m_szStoppedServerMsg;
|
|
}
|
|
else
|
|
{
|
|
// handle any other error (except empty db)
|
|
cstrViewErrorMsg = myGetErrorMessageText(hr, TRUE);
|
|
}
|
|
|
|
cstrStatusText.Format(g_pResources->m_szStatusBarErrorFormat, cstrViewErrorMsg);
|
|
|
|
m_pHeader->InsertColumn(0, W2COLE(L" "), LVCFMT_LEFT, 500); // Error
|
|
m_pConsole->SetStatusText((LPWSTR)(LPCWSTR)cstrStatusText);
|
|
}
|
|
|
|
//Ret:
|
|
if (pColSetData)
|
|
CoTaskMemFree(pColSetData);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LPCWSTR DescriptionStringFromFolderType(FOLDER_TYPES type)
|
|
{
|
|
ASSERT(NULL != g_pResources && g_pResources->m_fLoaded);
|
|
|
|
switch (type)
|
|
{
|
|
case SERVER_INSTANCE:
|
|
return (LPCWSTR) g_pResources->m_DescrStr_CA;
|
|
default:
|
|
break;
|
|
}
|
|
return (LPCWSTR)g_pResources->m_DescrStr_Unknown;
|
|
}
|
|
|
|
#define MMCVIEW_DB_MINPAGESIZE 32
|
|
#define MAX_VIEWABLE_STRING_LEN MAX_PATH
|
|
static WCHAR szVirtualStrBuf[MAX_VIEWABLE_STRING_LEN+1];
|
|
static DWORD cbVirtualStrBuf = sizeof(szVirtualStrBuf);
|
|
|
|
STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ASSERT(pResult != NULL);
|
|
|
|
if ((pResult) && (pResult->mask))
|
|
{
|
|
// a folder or a result?
|
|
if (pResult->bScopeItem)
|
|
{
|
|
CFolder* pFolder = reinterpret_cast<CFolder*>(pResult->lParam);
|
|
ASSERT(pFolder);
|
|
|
|
if (pResult->mask & RDI_STR)
|
|
{
|
|
switch (pFolder->m_type)
|
|
{
|
|
case MACHINE_INSTANCE:
|
|
case SERVER_INSTANCE:
|
|
switch(pResult->nCol)
|
|
{
|
|
case 0:
|
|
pResult->str = pFolder->m_pszName;
|
|
break;
|
|
case 1:
|
|
pResult->str = (LPOLESTR)DescriptionStringFromFolderType(pFolder->m_type);
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
// just a single column here
|
|
pResult->str = pFolder->m_pszName;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ASSERT(pResult->str != NULL);
|
|
|
|
if (pResult->str == NULL)
|
|
pResult->str = (LPOLESTR)L"";
|
|
}
|
|
|
|
if (pResult->mask & RDI_IMAGE)
|
|
{
|
|
if (pResult->nState & TVIS_EXPANDED)
|
|
pResult->nImage = pFolder->m_ScopeItem.nOpenImage;
|
|
else
|
|
pResult->nImage = pFolder->m_ScopeItem.nImage;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RESULT_DATA* pData = NULL;
|
|
CFolder* pFolder = NULL;
|
|
|
|
// if non-virtual, lParam is the item pointer
|
|
if (m_bVirtualView)
|
|
pFolder = GetVirtualFolder();
|
|
else
|
|
{
|
|
pData= reinterpret_cast<RESULT_DATA*>(pResult->lParam);
|
|
pFolder = pData->pParentFolder;
|
|
|
|
ASSERT(pData->pParentFolder == m_pCurrentlySelectedScopeFolder);
|
|
}
|
|
|
|
|
|
if (pResult->mask & RDI_STR)
|
|
{
|
|
switch(pFolder->GetType())
|
|
{
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
{
|
|
szVirtualStrBuf[0] = L'\0'; // zero
|
|
pResult->str = szVirtualStrBuf;
|
|
|
|
|
|
// have we had an error enumerating elts?
|
|
if (S_OK != m_dwViewErrorMsg)
|
|
{
|
|
// rtn err msg or blank
|
|
// ASSERT(pResult->nIndex == 0);
|
|
if (pResult->nIndex == 0)
|
|
pResult->str = (LPWSTR)(LPCWSTR)m_cstrViewErrorMsg;
|
|
|
|
break;
|
|
}
|
|
|
|
// Don't attempt to cache iViewCol -- we're asked
|
|
int iViewCol;
|
|
|
|
// if this request isn't the last one that came through, look it up
|
|
hr = m_RowEnum.GetColumnCacheInfo(
|
|
pResult->nCol,
|
|
&iViewCol);
|
|
_PrintIfError(hr, "GetColumnCacheInfo");
|
|
|
|
// HACKHACK
|
|
// if we get ErrorContinue, we should just take it
|
|
// in stride and return \0 (see GetColumnCacheInfo for details)
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_CONTINUE))
|
|
break;
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
// assume error
|
|
iViewCol = 0;
|
|
}
|
|
|
|
DWORD cbSize = cbVirtualStrBuf;
|
|
|
|
// protect ICertAdminD->EnumView from reentrant calls (see bug 339811)
|
|
if(2>InterlockedIncrement(&m_cViewCalls))
|
|
{
|
|
hr = GetCellContents(
|
|
&m_RowEnum,
|
|
pFolder->GetCA(),
|
|
pResult->nIndex,
|
|
pResult->nCol,
|
|
(PBYTE)szVirtualStrBuf,
|
|
&cbSize,
|
|
TRUE);
|
|
_PrintIfError2(hr, "GetCellContents", S_FALSE); // ignore end of db msg
|
|
}
|
|
|
|
InterlockedDecrement(&m_cViewCalls);
|
|
|
|
// only deal with 1st col
|
|
if (iViewCol != 0)
|
|
break;
|
|
|
|
// On Error
|
|
if ( (S_OK != hr) && (S_FALSE != hr) )
|
|
{
|
|
// stash error return
|
|
m_dwViewErrorMsg = hr;
|
|
|
|
if (!pFolder->GetCA()->m_pParentMachine->IsCertSvrServiceRunning())
|
|
{
|
|
// handle server stopped msg
|
|
|
|
// copy to stateful str
|
|
m_cstrViewErrorMsg = g_pResources->m_szStoppedServerMsg;
|
|
|
|
// copy to output
|
|
pResult->str = (LPWSTR)(LPCWSTR)g_pResources->m_szStoppedServerMsg;
|
|
}
|
|
else
|
|
{
|
|
// handle any other error (except empty db)
|
|
m_cstrViewErrorMsg = myGetErrorMessageText(hr, TRUE);
|
|
|
|
// truncate if necessary
|
|
ASSERT(MAX_VIEWABLE_STRING_LEN >= wcslen((LPWSTR)(LPCWSTR)m_cstrViewErrorMsg) );
|
|
if (MAX_VIEWABLE_STRING_LEN < wcslen((LPWSTR)(LPCWSTR)m_cstrViewErrorMsg) )
|
|
m_cstrViewErrorMsg.SetAt(MAX_VIEWABLE_STRING_LEN, L'\0');
|
|
|
|
pResult->str = (LPWSTR)(LPCWSTR)m_cstrViewErrorMsg;
|
|
}
|
|
|
|
// on error, just display this msg
|
|
if (!m_RowEnum.m_fKnowNumResultRows)
|
|
{
|
|
// upd view
|
|
SetKnowResultRows(1);
|
|
m_pResult->SetItemCount(1, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
|
|
|
|
// don't destroy column widths!
|
|
// OLD: make col width large enough to hold msg
|
|
// m_pHeader->SetColumnWidth(0, CHARS_TO_MMCCOLUMNWIDTH(wcslen(pResult->str)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
// if 1st col and don't know the final tally, might have to update best guess
|
|
if (hr == S_OK)
|
|
{
|
|
if (KnownResultRows() == (DWORD)(pResult->nIndex+1))
|
|
// if asking for the last element (ones based)
|
|
{
|
|
// next guess at end
|
|
BOOL fSetViewCount = FALSE;
|
|
DWORD dwNextEnd = 0;
|
|
|
|
if (!m_RowEnum.m_fKnowNumResultRows) // only make guess if enum doesn't have a clue yet
|
|
{
|
|
// double where we are now, make sure we're at least moving MMCVIEW_DB_MINPAGESIZE rows
|
|
dwNextEnd = max( ((pResult->nIndex+1)*2), MMCVIEW_DB_MINPAGESIZE);
|
|
|
|
DBGPRINT((DBG_SS_CERTMMC, "RowEnum dwResultRows = %i, requested Index = %i. Creating Guess = %i\n", m_RowEnum.m_dwResultRows, pResult->nIndex, dwNextEnd));
|
|
|
|
// upd enumerator with our best guess
|
|
fSetViewCount = TRUE;
|
|
}
|
|
else if (KnownResultRows() != m_RowEnum.m_dwResultRows)
|
|
{
|
|
dwNextEnd = m_RowEnum.m_dwResultRows;
|
|
fSetViewCount = TRUE;
|
|
}
|
|
|
|
// upd view
|
|
if (fSetViewCount)
|
|
{
|
|
SetKnowResultRows(dwNextEnd);
|
|
m_pResult->SetItemCount(dwNextEnd, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
|
|
}
|
|
|
|
} // if the enumerator doesn't have a clue yet
|
|
}
|
|
else
|
|
{
|
|
ASSERT(hr == S_FALSE);
|
|
|
|
// end-of-db should only come on first col
|
|
// if error while retrieving first elt in row, ASSUME end of DB
|
|
LONG lRetrievedIndex;
|
|
hr = m_RowEnum.GetRowMaxIndex(pFolder->GetCA(), &lRetrievedIndex);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
DBGPRINT((DBG_SS_CERTMMC, "Hit end, setting max index to %i\n", lRetrievedIndex));
|
|
|
|
SetKnowResultRows(lRetrievedIndex);
|
|
m_pResult->SetItemCount(lRetrievedIndex, MMCLV_UPDATE_NOSCROLL | MMCLV_UPDATE_NOINVALIDATEALL);
|
|
// m_pResult->ModifyItemState(lRetrievedIndex-1, 0, (LVIS_FOCUSED | LVIS_SELECTED), 0); // set focus to last item
|
|
// BUG BUG MMC fails to re-select scope pane when we set selection here, so just set focus (build 2010)
|
|
if (lRetrievedIndex != 0)
|
|
m_pResult->ModifyItemState(lRetrievedIndex-1, 0, LVIS_FOCUSED, 0); // set focus to last item
|
|
}
|
|
} // end case
|
|
break;
|
|
case SERVER_INSTANCE:
|
|
default: // try this, no guarantee
|
|
if (NULL == pData)
|
|
break;
|
|
ASSERT(pResult->nCol < (int)pData->cStringArray);
|
|
pResult->str = (LPOLESTR)pData->szStringArray[pResult->nCol];
|
|
break;
|
|
}
|
|
|
|
ASSERT(pResult->str != NULL);
|
|
|
|
if (pResult->str == NULL)
|
|
pResult->str = (LPOLESTR)L"";
|
|
}
|
|
|
|
// MMC can request image and indent for virtual data
|
|
if (pResult->mask & RDI_IMAGE)
|
|
{
|
|
if ((pResult->nIndex >= (int)m_RowEnum.m_dwResultRows) || (hr != S_OK) || (S_OK != m_dwViewErrorMsg))
|
|
{
|
|
// MMC bug: using SetItemCount doesn't stick early enough to keep it from
|
|
// asking for icons for the first page.
|
|
pResult->nImage = IMGINDEX_NO_IMAGE;
|
|
}
|
|
else
|
|
{
|
|
switch(pFolder->GetType())
|
|
{
|
|
case SERVERFUNC_FAILED_CERTIFICATES:
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
pResult->nImage = IMGINDEX_CRL;
|
|
break;
|
|
case SERVERFUNC_PENDING_CERTIFICATES:
|
|
pResult->nImage = IMGINDEX_PENDING_CERT;
|
|
break;
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
pResult->nImage = IMGINDEX_CERT;
|
|
break;
|
|
default:
|
|
// should never get here
|
|
ASSERT(0);
|
|
pResult->nImage = IMGINDEX_NO_IMAGE;
|
|
break;
|
|
} // end switch
|
|
} // end > rows test
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IExtendContextMenu Implementation
|
|
STDMETHODIMP CSnapin::AddMenuItems(LPDATAOBJECT pDataObject,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LONG *pInsertionAllowed)
|
|
{
|
|
dynamic_cast<CComponentDataImpl*>(m_pComponentData)->m_pCurSelFolder = m_pCurrentlySelectedScopeFolder;
|
|
|
|
HRESULT hr;
|
|
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
|
|
if (NULL == pInternal)
|
|
return S_OK;
|
|
|
|
BOOL bMultiSel = IsMMCMultiSelectDataObject(pDataObject);
|
|
|
|
BOOL fResultItem = (pInternal->m_type == CCT_RESULT);
|
|
|
|
CFolder* pFolder = m_pCurrentlySelectedScopeFolder;
|
|
|
|
FOLDER_TYPES folderType = NONE;
|
|
if (pFolder == NULL)
|
|
folderType = MACHINE_INSTANCE;
|
|
else
|
|
folderType = pFolder->GetType();
|
|
|
|
hr = dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
|
|
AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed);
|
|
if (hr != S_OK)
|
|
goto Ret;
|
|
|
|
// Loop through and add each of the view items
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW)
|
|
{
|
|
// fixup entries
|
|
MY_CONTEXTMENUITEM* pm = viewResultItems;
|
|
|
|
if (m_RowEnum.FAreQueryRestrictionsActive(SERVERFUNC_ISSUED_CRLS != folderType)) // filtered?
|
|
{
|
|
pm[ENUM_VIEW_FILTER].item.fFlags =
|
|
MFT_RADIOCHECK | MFS_CHECKED | MFS_ENABLED;
|
|
pm[ENUM_VIEW_ALL].item.fFlags =
|
|
MFS_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
pm[ENUM_VIEW_FILTER].item.fFlags =
|
|
MFS_ENABLED;
|
|
pm[ENUM_VIEW_ALL].item.fFlags =
|
|
MFT_RADIOCHECK | MFS_CHECKED | MFS_ENABLED;
|
|
}
|
|
|
|
for (; pm->item.strName; pm++)
|
|
{
|
|
// show in both scope/result panes
|
|
// fResultItem
|
|
|
|
// Only support views in known containers
|
|
// for each task, insert if matches the current folder
|
|
if ((folderType == SERVERFUNC_CRL_PUBLICATION) ||
|
|
(folderType == SERVERFUNC_ISSUED_CERTIFICATES) ||
|
|
(folderType == SERVERFUNC_PENDING_CERTIFICATES) ||
|
|
(folderType == SERVERFUNC_ALIEN_CERTIFICATES) ||
|
|
(folderType == SERVERFUNC_FAILED_CERTIFICATES) ||
|
|
(folderType == SERVERFUNC_ISSUED_CERTIFICATES) ||
|
|
(folderType == SERVERFUNC_ISSUED_CRLS))
|
|
{
|
|
hr = pContextMenuCallback->AddItem(&pm->item);
|
|
_JumpIfError(hr, Ret, "AddItem");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK)
|
|
{
|
|
// ptr to tasks
|
|
TASKITEM* pm = taskResultItemsSingleSel;
|
|
|
|
if (!bMultiSel)
|
|
{
|
|
// insert all other tasks per folder
|
|
for (; pm->myitem.item.strName; pm++)
|
|
{
|
|
// does it match scope/result type?
|
|
// if (value where we are !=
|
|
// whether or not the resultitem bit is set)
|
|
if (fResultItem != (0 != (pm->dwFlags & TASKITEM_FLAG_RESULTITEM)) )
|
|
continue;
|
|
|
|
// does it match area it should be in?
|
|
// for each task, insert if matches the current folder
|
|
if (folderType != pm->type)
|
|
continue;
|
|
|
|
// is this task supposed to be hidden?
|
|
if (MFS_HIDDEN == pm->myitem.item.fFlags)
|
|
continue;
|
|
|
|
if(!((pm->myitem.dwRoles) & (pFolder->m_pCertCA->GetMyRoles())))
|
|
pm->myitem.item.fFlags = MFS_GRAYED;
|
|
|
|
hr = pContextMenuCallback->AddItem(&pm->myitem.item);
|
|
_JumpIfError(hr, Ret, "AddItem");
|
|
}
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
FREE_DATA(pInternal);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSnapin::Command(LONG nCommandID, LPDATAOBJECT pDataObject)
|
|
{
|
|
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
|
|
if (pInternal == NULL)
|
|
return E_FAIL;
|
|
|
|
BOOL fConfirmedAction = FALSE;
|
|
BOOL fMustRefresh = FALSE;
|
|
|
|
LONG lReasonCode = CRL_REASON_UNSPECIFIED;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CFolder* pFolder = GetParentFolder(pInternal);
|
|
ICertAdmin* pAdmin = NULL; // free this
|
|
CWaitCursor* pcwait = NULL; // some of these commands are multiselect and could take awhile.
|
|
// On those that are lengthy, this will be created and needs to be deleted at exit
|
|
|
|
if (pInternal->m_type == CCT_SCOPE)
|
|
{
|
|
// Handle view specific commands here
|
|
switch (nCommandID)
|
|
{
|
|
case MMCC_STANDARD_VIEW_SELECT:
|
|
m_CustomViewID = VIEW_DEFAULT_LV;
|
|
break;
|
|
case IDC_VIEW_ALLRECORDS:
|
|
{
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
// if restricted view, change
|
|
BOOL fCertView = SERVERFUNC_ISSUED_CRLS != pFolder->GetType();
|
|
if (m_RowEnum.FAreQueryRestrictionsActive(fCertView))
|
|
{
|
|
// switch off active flag
|
|
m_RowEnum.SetQueryRestrictionsActive(FALSE, fCertView);
|
|
|
|
// refresh just this folder
|
|
OnRefresh(pDataObject);
|
|
SetDirty();
|
|
}
|
|
|
|
break;
|
|
}
|
|
case IDC_VIEW_FILTER:
|
|
{
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
HWND hwnd;
|
|
hr = m_pConsole->GetMainWindow(&hwnd);
|
|
ASSERT(hr == ERROR_SUCCESS);
|
|
if (hr != ERROR_SUCCESS)
|
|
hwnd = NULL; // should work
|
|
|
|
hr = ModifyQueryFilter(hwnd, &m_RowEnum, dynamic_cast<CComponentDataImpl*>(m_pComponentData), SERVERFUNC_ISSUED_CRLS != pFolder->GetType());
|
|
|
|
// refresh only if successful
|
|
if (hr == ERROR_SUCCESS)
|
|
{
|
|
// refresh just this folder
|
|
OnRefresh(pDataObject);
|
|
SetDirty();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
// Pass non-view specific commands to ComponentData
|
|
return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
|
|
Command(nCommandID, pDataObject);
|
|
}
|
|
}
|
|
else if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
// get this only ONCE, it's freed later
|
|
if ((nCommandID == IDC_RESUBMITREQUEST) ||
|
|
(nCommandID == IDC_DENYREQUEST) ||
|
|
(nCommandID == IDC_REVOKECERT) ||
|
|
(nCommandID == IDC_UNREVOKE_CERT))
|
|
{
|
|
if (pFolder == NULL)
|
|
{
|
|
hr = E_POINTER;
|
|
goto ExitCommand;
|
|
}
|
|
|
|
// have pAdmin allocated
|
|
hr = pFolder->GetCA()->m_pParentMachine->GetAdmin(&pAdmin);
|
|
if (S_OK != hr)
|
|
goto ExitCommand;
|
|
}
|
|
|
|
// snag the selected items
|
|
|
|
RESULTDATAITEM rdi;
|
|
rdi.mask = RDI_STATE;
|
|
|
|
rdi.nState = LVIS_SELECTED;
|
|
rdi.nIndex = -1;
|
|
|
|
|
|
// must sit outside loop so multi-select works
|
|
LPCWSTR szCol=NULL; // don't free
|
|
BOOL fSaveInstead = FALSE;
|
|
|
|
|
|
while(S_OK == m_pResult->GetNextItem(&rdi))
|
|
{
|
|
// Handle each of the commands seperately
|
|
switch (nCommandID)
|
|
{
|
|
case IDC_VIEW_CERT_PROPERTIES:
|
|
{
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
switch (pFolder->GetType())
|
|
{
|
|
case SERVERFUNC_ISSUED_CERTIFICATES:
|
|
case SERVERFUNC_CRL_PUBLICATION:
|
|
case SERVERFUNC_ALIEN_CERTIFICATES:
|
|
{
|
|
CertSvrCA* pCA = pFolder->GetCA();
|
|
CRYPTUI_VIEWCERTIFICATE_STRUCTW sViewCert;
|
|
ZeroMemory(&sViewCert, sizeof(sViewCert));
|
|
HCERTSTORE rghStores[2]; // don't close these stores
|
|
|
|
// get this cert
|
|
PBYTE pbCert = NULL;
|
|
DWORD cbCert;
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPRAWCERTIFICATE, &pbCert, &cbCert);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
sViewCert.pCertContext = CertCreateCertificateContext(
|
|
CRYPT_ASN_ENCODING,
|
|
pbCert,
|
|
cbCert);
|
|
delete [] pbCert;
|
|
|
|
if (sViewCert.pCertContext == NULL)
|
|
break;
|
|
|
|
hr = m_pConsole->GetMainWindow(&sViewCert.hwndParent);
|
|
if (S_OK != hr)
|
|
sViewCert.hwndParent = NULL; // should work
|
|
|
|
sViewCert.dwSize = sizeof(sViewCert);
|
|
sViewCert.dwFlags = CRYPTUI_ENABLE_REVOCATION_CHECKING | CRYPTUI_DISABLE_ADDTOSTORE;
|
|
|
|
// if we're opening remotely, don't open local stores
|
|
if (! pCA->m_pParentMachine->IsLocalMachine())
|
|
{
|
|
DWORD dw;
|
|
|
|
// get remote stores
|
|
dw = pCA->GetRootCertStore(&rghStores[0]);
|
|
_PrintIfError(dw, "GetRootCertStore");
|
|
|
|
if (S_OK == dw)
|
|
{
|
|
dw = pCA->GetCACertStore(&rghStores[1]);
|
|
_PrintIfError(dw, "GetCACertStore");
|
|
}
|
|
|
|
if (S_OK == dw)
|
|
{
|
|
// rely only on remote machine's stores
|
|
sViewCert.cStores = 2;
|
|
sViewCert.rghStores = rghStores;
|
|
sViewCert.dwFlags |= CRYPTUI_DONT_OPEN_STORES | CRYPTUI_WARN_UNTRUSTED_ROOT;
|
|
}
|
|
else
|
|
{
|
|
// tell user we're only doing this locally
|
|
sViewCert.dwFlags |= CRYPTUI_WARN_REMOTE_TRUST;
|
|
}
|
|
}
|
|
|
|
if (!CryptUIDlgViewCertificateW(&sViewCert, NULL))
|
|
hr = GetLastError();
|
|
|
|
VERIFY(CertFreeCertificateContext(sViewCert.pCertContext));
|
|
}
|
|
break;
|
|
|
|
case SERVERFUNC_ISSUED_CRLS:
|
|
{
|
|
CertSvrCA* pCA = pFolder->GetCA();
|
|
CRYPTUI_VIEWCRL_STRUCTW sViewCRL;
|
|
ZeroMemory(&sViewCRL, sizeof(sViewCRL));
|
|
HCERTSTORE rghStores[2]; // don't close these stores
|
|
|
|
// get this CRL
|
|
PBYTE pbCRL = NULL;
|
|
DWORD cbCRL;
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPCRLRAWCRL, &pbCRL, &cbCRL);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
sViewCRL.pCRLContext = CertCreateCRLContext(
|
|
CRYPT_ASN_ENCODING,
|
|
pbCRL,
|
|
cbCRL);
|
|
delete [] pbCRL;
|
|
|
|
if (sViewCRL.pCRLContext == NULL)
|
|
break;
|
|
|
|
hr = m_pConsole->GetMainWindow(&sViewCRL.hwndParent);
|
|
if (S_OK != hr)
|
|
sViewCRL.hwndParent = NULL; // should work
|
|
|
|
sViewCRL.dwSize = sizeof(sViewCRL);
|
|
//sViewCRL.dwFlags = 0;
|
|
|
|
// if we're opening remotely, don't open local stores
|
|
if (! pCA->m_pParentMachine->IsLocalMachine())
|
|
{
|
|
DWORD dw;
|
|
|
|
// get remote stores
|
|
dw = pCA->GetRootCertStore(&rghStores[0]);
|
|
_PrintIfError(dw, "GetRootCertStore");
|
|
|
|
if (S_OK == dw)
|
|
{
|
|
dw = pCA->GetCACertStore(&rghStores[1]);
|
|
_PrintIfError(dw, "GetCACertStore");
|
|
}
|
|
|
|
if (S_OK == dw)
|
|
{
|
|
// rely only on remote machine's stores
|
|
sViewCRL.cStores = 2;
|
|
sViewCRL.rghStores = rghStores;
|
|
sViewCRL.dwFlags |= CRYPTUI_DONT_OPEN_STORES | CRYPTUI_WARN_UNTRUSTED_ROOT;
|
|
}
|
|
else
|
|
{
|
|
// tell user we're only doing this locally
|
|
sViewCRL.dwFlags |= CRYPTUI_WARN_REMOTE_TRUST;
|
|
}
|
|
}
|
|
|
|
if (!CryptUIDlgViewCRLW(&sViewCRL))
|
|
hr = GetLastError();
|
|
|
|
VERIFY(CertFreeCRLContext(sViewCRL.pCRLContext));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case IDC_RESUBMITREQUEST:
|
|
{
|
|
LPWSTR szReqID = NULL;
|
|
DWORD cbReqID;
|
|
LONG lReqID;
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
if (pcwait == NULL) // this might take awhile
|
|
pcwait = new CWaitCursor;
|
|
|
|
// "Request.RequestID"
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
lReqID = _wtol(szReqID);
|
|
delete [] szReqID;
|
|
|
|
hr = CertAdminResubmitRequest(pFolder->GetCA(), pAdmin, lReqID);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// dirty pane: refresh
|
|
fMustRefresh = TRUE;
|
|
|
|
break;
|
|
}
|
|
case IDC_DENYREQUEST:
|
|
{
|
|
LPWSTR szReqID = NULL;
|
|
DWORD cbReqID;
|
|
LONG lReqID;
|
|
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
// "Request.RequestID"
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
lReqID = _wtol(szReqID);
|
|
delete [] szReqID;
|
|
|
|
if (!fConfirmedAction)
|
|
{
|
|
// confirm this action
|
|
CString cstrMsg, cstrTitle;
|
|
cstrMsg.LoadString(IDS_CONFIRM_DENY_REQUEST);
|
|
cstrTitle.LoadString(IDS_DENY_REQUEST_TITLE);
|
|
int iRet;
|
|
if ((S_OK != m_pConsole->MessageBox(cstrMsg, cstrTitle, MB_YESNO, &iRet)) ||
|
|
(iRet != IDYES))
|
|
{
|
|
hr = ERROR_CANCELLED;
|
|
goto ExitCommand;
|
|
}
|
|
|
|
fConfirmedAction = TRUE;
|
|
}
|
|
|
|
if (pcwait == NULL) // this might take awhile
|
|
pcwait = new CWaitCursor;
|
|
|
|
hr = CertAdminDenyRequest(pFolder->GetCA(), pAdmin, lReqID);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// dirty pane: refresh
|
|
fMustRefresh = TRUE;
|
|
|
|
break;
|
|
}
|
|
case IDC_VIEW_ATTR_EXT:
|
|
{
|
|
IEnumCERTVIEWEXTENSION* pExtn = NULL;
|
|
IEnumCERTVIEWATTRIBUTE* pAttr = NULL;
|
|
LPWSTR szReqID = NULL;
|
|
DWORD cbReqID;
|
|
HWND hwnd;
|
|
|
|
ASSERT(pInternal->m_type == CCT_RESULT);
|
|
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
hr = m_pConsole->GetMainWindow(&hwnd);
|
|
if (S_OK != hr)
|
|
hwnd = NULL; // should work
|
|
|
|
// "Request.RequestID"
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREQUESTID, (PBYTE*)&szReqID, &cbReqID, TRUE);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
// pollute the row enumerator we've got (doesn't alloc new IF)
|
|
hr = m_RowEnum.SetRowEnumPos(rdi.nIndex);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
IEnumCERTVIEWROW* pRow;
|
|
hr = m_RowEnum.GetRowEnum(pFolder->GetCA(), &pRow);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pRow->EnumCertViewAttribute(0, &pAttr);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = pRow->EnumCertViewExtension(0, &pExtn);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
hr = ViewRowAttributesExtensions(hwnd, pAttr, pExtn, szReqID);
|
|
delete [] szReqID;
|
|
if (pExtn)
|
|
pExtn->Release();
|
|
if (pAttr)
|
|
pAttr->Release();
|
|
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
break;
|
|
}
|
|
|
|
case IDC_DUMP_ASN:
|
|
{
|
|
PBYTE pbReq = NULL;
|
|
DWORD cbReq;
|
|
CString cstrFileName;
|
|
LPCWSTR pszLocalizedCol = NULL;
|
|
|
|
ASSERT(pInternal->m_type == CCT_RESULT);
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
HWND hwnd;
|
|
|
|
hr = m_pConsole->GetMainWindow(&hwnd);
|
|
if (S_OK != hr)
|
|
hwnd = NULL; // should work
|
|
|
|
if (!fConfirmedAction)
|
|
{
|
|
hr = ChooseBinaryColumnToDump(hwnd, pData, &szCol, &fSaveInstead);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
if (szCol == NULL) // strangeness
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
fConfirmedAction = TRUE;
|
|
}
|
|
|
|
// "Request.RequestID"
|
|
hr = GetRowColContents(
|
|
pFolder,
|
|
rdi.nIndex,
|
|
SERVERFUNC_ISSUED_CRLS == pFolder->GetType()?
|
|
wszPROPCRLROWID :
|
|
wszPROPREQUESTDOT wszPROPREQUESTREQUESTID,
|
|
(PBYTE*)&pbReq,
|
|
&cbReq,
|
|
TRUE);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
hr = myGetColumnDisplayName(szCol, &pszLocalizedCol);
|
|
if ((hr != S_OK) || (pszLocalizedCol == NULL))
|
|
pszLocalizedCol = L"";
|
|
|
|
cstrFileName = pszLocalizedCol;
|
|
cstrFileName += L" - ";
|
|
cstrFileName += (LPCWSTR)pbReq;
|
|
cstrFileName += L".tmp";
|
|
delete [] pbReq;
|
|
|
|
// get the request
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, szCol, &pbReq, &cbReq);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
hr = ViewRowRequestASN(hwnd, cstrFileName, pbReq, cbReq, fSaveInstead);
|
|
delete [] pbReq;
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
break;
|
|
}
|
|
case IDC_UNREVOKE_CERT:
|
|
{
|
|
ASSERT(pInternal->m_type == CCT_RESULT);
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
LPWSTR szCertSerNum = NULL;
|
|
DWORD cbSerNum;
|
|
PBYTE pbRevocationReason = NULL;
|
|
DWORD cbRevocationReason;
|
|
|
|
HWND hwnd;
|
|
hr = m_pConsole->GetMainWindow(&hwnd);
|
|
if (S_OK != hr)
|
|
hwnd = NULL; // should work
|
|
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPREQUESTDOT wszPROPREQUESTREVOKEDREASON, &pbRevocationReason, &cbRevocationReason);
|
|
if (S_OK != hr)
|
|
break;
|
|
if ((cbRevocationReason != sizeof(DWORD)) || (*(DWORD*)pbRevocationReason != CRL_REASON_CERTIFICATE_HOLD))
|
|
{
|
|
delete [] pbRevocationReason;
|
|
DisplayCertSrvErrorWithContext(hwnd, S_OK, IDS_UNREVOKE_FAILED); // don't display hokey "invalid state" error, just nice text
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
delete [] pbRevocationReason;
|
|
// otherwise, continue
|
|
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPCERTIFICATESERIALNUMBER, (PBYTE*)&szCertSerNum, &cbSerNum);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
// zero terminate
|
|
WCHAR szTmpSerNum[MAX_PATH+1];
|
|
CopyMemory(szTmpSerNum, szCertSerNum, cbSerNum);
|
|
ASSERT((cbSerNum & 0x1) == 0x00); // better be even!
|
|
szTmpSerNum[cbSerNum>>1] = 0x00;
|
|
delete [] szCertSerNum;
|
|
|
|
hr = CertAdminRevokeCert(pFolder->GetCA(), pAdmin, MAXDWORD, szTmpSerNum); // MAXDWORD == unrevoke
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// dirty pane: refresh
|
|
fMustRefresh = TRUE;
|
|
break;
|
|
}
|
|
|
|
case IDC_REVOKECERT:
|
|
{
|
|
ASSERT(pInternal->m_type == CCT_RESULT);
|
|
if (NULL == pFolder)
|
|
break;
|
|
|
|
LPWSTR szCertSerNum = NULL;
|
|
DWORD cbSerNum;
|
|
|
|
hr = GetRowColContents(pFolder, rdi.nIndex, wszPROPCERTIFICATESERIALNUMBER, (PBYTE*)&szCertSerNum, &cbSerNum);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
// zero terminate
|
|
WCHAR szTmpSerNum[MAX_PATH+1];
|
|
CopyMemory(szTmpSerNum, szCertSerNum, cbSerNum);
|
|
ASSERT((cbSerNum & 0x1) == 0x00); // better be even!
|
|
szTmpSerNum[cbSerNum>>1] = 0x00;
|
|
delete [] szCertSerNum;
|
|
|
|
if (!fConfirmedAction)
|
|
{
|
|
HWND hwnd;
|
|
hr = m_pConsole->GetMainWindow(&hwnd);
|
|
if (S_OK != hr)
|
|
hwnd = NULL; // should work
|
|
|
|
hr = GetUserConfirmRevocationReason(&lReasonCode, hwnd);
|
|
if (hr != S_OK)
|
|
goto ExitCommand;
|
|
|
|
fConfirmedAction = TRUE;
|
|
}
|
|
if (pcwait == NULL) // this might take awhile
|
|
pcwait = new CWaitCursor;
|
|
|
|
hr = CertAdminRevokeCert(pFolder->GetCA(), pAdmin, lReasonCode, szTmpSerNum);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
// dirty pane: refresh
|
|
fMustRefresh = TRUE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ASSERT(FALSE); // Unknown command!
|
|
break;
|
|
}
|
|
|
|
|
|
// if ever the user says stop, halt everything
|
|
if (((HRESULT)ERROR_CANCELLED) == hr)
|
|
goto ExitCommand;
|
|
} // end loop
|
|
} // if result
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
ExitCommand:
|
|
FREE_DATA(pInternal);
|
|
|
|
if (pcwait != NULL)
|
|
delete pcwait;
|
|
|
|
// might've been cached over multiple selections
|
|
if (pAdmin)
|
|
pAdmin->Release();
|
|
|
|
if ((hr != S_OK) && (hr != ERROR_CANCELLED) && (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED)))
|
|
DisplayGenericCertSrvError(m_pConsole, hr);
|
|
|
|
// only do this once
|
|
if (fMustRefresh)
|
|
{
|
|
// notify views: refresh service toolbar buttons
|
|
m_pConsole->UpdateAllViews(
|
|
pDataObject,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::GetClassID(CLSID *pClassID)
|
|
{
|
|
ASSERT(pClassID != NULL);
|
|
|
|
// Copy the CLSID for this snapin
|
|
*pClassID = CLSID_Snapin;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::IsDirty()
|
|
{
|
|
// Always save / Always dirty.
|
|
return ThisIsDirty() ? S_OK : S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Load(IStream *pStm)
|
|
{
|
|
HRESULT hr;
|
|
ASSERT(m_bInitializedC);
|
|
ASSERT(pStm);
|
|
|
|
// Read the string
|
|
DWORD dwVer;
|
|
|
|
hr = ReadOfSize(pStm, &dwVer, sizeof(DWORD));
|
|
_JumpIfError(hr, Ret, "Load: dwVer");
|
|
|
|
ASSERT((VER_CSNAPIN_SAVE_STREAM_3 == dwVer) || (VER_CSNAPIN_SAVE_STREAM_2 == dwVer));
|
|
if ((VER_CSNAPIN_SAVE_STREAM_3 != dwVer) &&
|
|
(VER_CSNAPIN_SAVE_STREAM_2 != dwVer))
|
|
{
|
|
hr = STG_E_OLDFORMAT;
|
|
_JumpError(hr, Ret, "dwVer");
|
|
}
|
|
|
|
// version-dependent info
|
|
if (VER_CSNAPIN_SAVE_STREAM_3 == dwVer)
|
|
{
|
|
// View ID
|
|
hr = ReadOfSize(pStm, &m_dwViewID, sizeof(DWORD));
|
|
_JumpIfError(hr, Ret, "Load: m_dwViewID");
|
|
|
|
// row enum
|
|
hr = m_RowEnum.Load(pStm);
|
|
_JumpIfError(hr, Ret, "Load::m_RowEnum");
|
|
}
|
|
|
|
Ret:
|
|
ClearDirty();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSnapin::Save(IStream *pStm, BOOL fClearDirty)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ASSERT(m_bInitializedC);
|
|
ASSERT(pStm);
|
|
|
|
// Write the version
|
|
DWORD dwVer = VER_CSNAPIN_SAVE_STREAM_3;
|
|
|
|
hr = WriteOfSize(pStm, &dwVer, sizeof(DWORD));
|
|
_JumpIfError(hr, Ret, "Save: dwVer");
|
|
|
|
// View ID
|
|
hr = WriteOfSize(pStm, &m_dwViewID, sizeof(DWORD));
|
|
_JumpIfError(hr, Ret, "Save: m_dwViewID");
|
|
|
|
hr = m_RowEnum.Save(pStm, fClearDirty);
|
|
_JumpIfError(hr, Ret, "Save::m_RowEnum");
|
|
|
|
Ret:
|
|
if (fClearDirty)
|
|
ClearDirty();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
|
{
|
|
ASSERT(pcbSize);
|
|
|
|
DWORD cbSize;
|
|
cbSize = sizeof(DWORD); // Version
|
|
|
|
cbSize += sizeof(DWORD); // m_dwViewID
|
|
|
|
int iAdditionalSize = 0;
|
|
m_RowEnum.GetSizeMax(&iAdditionalSize);
|
|
cbSize += iAdditionalSize;
|
|
|
|
// Set the size of the string to be saved
|
|
ULISet32(*pcbSize, cbSize);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IExtendPropertySheet implementation
|
|
//
|
|
STDMETHODIMP
|
|
CSnapin::CreatePropertyPages(
|
|
LPPROPERTYSHEETCALLBACK, // lpProvider
|
|
LONG_PTR, // handle
|
|
LPDATAOBJECT) // lpIDataObject
|
|
{
|
|
// no property pages
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CSnapin::QueryPagesFor(
|
|
LPDATAOBJECT) // lpDataObject
|
|
{
|
|
// Get the node type and see if it's one of mine
|
|
|
|
// if (nodetype == one of mine)
|
|
// do this
|
|
// else
|
|
// see which node type it is and answer the question
|
|
|
|
BOOL bResult = FALSE;
|
|
|
|
return (bResult) ? S_OK : S_FALSE;
|
|
|
|
// Look at the data object and see if it an item in the scope pane
|
|
// return IsScopePaneNode(lpDataObject) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IExtendControlbar implementation
|
|
//
|
|
|
|
|
|
STDMETHODIMP CSnapin::SetControlbar(LPCONTROLBAR pControlbar)
|
|
{
|
|
if (m_pControlbar)
|
|
SAFE_RELEASE(m_pControlbar);
|
|
|
|
if (pControlbar != NULL)
|
|
{
|
|
// Hold on to the controlbar interface.
|
|
m_pControlbar = pControlbar;
|
|
m_pControlbar->AddRef();
|
|
|
|
HRESULT hr=S_FALSE;
|
|
|
|
// SvrMgrToolbar1
|
|
if (!m_pSvrMgrToolbar1)
|
|
{
|
|
hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pSvrMgrToolbar1));
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
// Add the bitmap
|
|
ASSERT(NULL != g_pResources && g_pResources->m_fLoaded);
|
|
hr = m_pSvrMgrToolbar1->AddBitmap(2, g_pResources->m_bmpSvrMgrToolbar1, 16, 16, RGB(192,192,192));
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
// Add the buttons to the toolbar
|
|
for (int i=0; ((SvrMgrToolbar1Buttons[i].item.lpButtonText != NULL) && (SvrMgrToolbar1Buttons[i].item.lpTooltipText != NULL)); i++)
|
|
{
|
|
hr = m_pSvrMgrToolbar1->AddButtons(1, &SvrMgrToolbar1Buttons[i].item);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void CSnapin::OnButtonClick(LPDATAOBJECT pdtobj, int idBtn)
|
|
{
|
|
|
|
switch(idBtn)
|
|
{
|
|
case IDC_STOPSERVER:
|
|
case IDC_STARTSERVER:
|
|
// bubble this to our other handler
|
|
dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
|
|
Command(idBtn, pdtobj);
|
|
break;
|
|
default:
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSnapin::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
|
|
{
|
|
switch (event)
|
|
{
|
|
case MMCN_BTN_CLICK:
|
|
OnButtonClick(reinterpret_cast<LPDATAOBJECT>(arg), (INT)param);
|
|
break;
|
|
|
|
case MMCN_DESELECT_ALL:
|
|
case MMCN_SELECT:
|
|
HandleExtToolbars((event == MMCN_DESELECT_ALL), arg, param);
|
|
break;
|
|
|
|
case MMCN_MENU_BTNCLICK:
|
|
HandleExtMenus(arg, param);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// This compares two data objects to see if they are the same object.
|
|
// return
|
|
// S_OK if equal otherwise S_FALSE
|
|
//
|
|
// Note: check to make sure both objects belong to the snap-in.
|
|
//
|
|
|
|
STDMETHODIMP
|
|
CSnapin::CompareObjects(
|
|
LPDATAOBJECT, // lpDataObjectA
|
|
LPDATAOBJECT) // lpDataObjectB
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
// This compare is used to sort the items in the listview
|
|
//
|
|
// Parameters:
|
|
//
|
|
// lUserParam - user param passed in when IResultData::Sort() was called
|
|
// cookieA - first item to compare
|
|
// cookieB - second item to compare
|
|
// pnResult [in, out]- contains the col on entry,
|
|
// -1, 0, 1 based on comparison for return value.
|
|
//
|
|
// Note: Assume sort is ascending when comparing -- mmc reverses the result if it needs to
|
|
STDMETHODIMP
|
|
CSnapin::Compare(
|
|
LPARAM, // lUserParam
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int* pnResult)
|
|
{
|
|
if (pnResult == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_POINTER;
|
|
}
|
|
|
|
// check col range
|
|
LONG nCol = (LONG) *pnResult;
|
|
ASSERT(nCol >=0);
|
|
|
|
*pnResult = 0;
|
|
|
|
USES_CONVERSION;
|
|
|
|
LPWSTR szStringA;
|
|
LPWSTR szStringB;
|
|
|
|
RESULT_DATA* pDataA = reinterpret_cast<RESULT_DATA*>(cookieA);
|
|
RESULT_DATA* pDataB = reinterpret_cast<RESULT_DATA*>(cookieB);
|
|
|
|
|
|
ASSERT(pDataA != NULL && pDataB != NULL);
|
|
|
|
ASSERT(nCol < (int)pDataA->cStringArray);
|
|
ASSERT(nCol < (int)pDataB->cStringArray);
|
|
|
|
szStringA = OLE2T(pDataA->szStringArray[nCol]);
|
|
szStringB = OLE2T(pDataB->szStringArray[nCol]);
|
|
|
|
ASSERT(szStringA != NULL);
|
|
ASSERT(szStringB != NULL);
|
|
|
|
if ((szStringA == NULL) || (szStringB == NULL))
|
|
return E_POINTER;
|
|
|
|
|
|
// return simple strcmp
|
|
*pnResult = wcscmp(szStringA, szStringB);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CSnapin::FindItem(
|
|
LPRESULTFINDINFO, // pFindInfo
|
|
int *) // pnFoundIndex
|
|
{
|
|
// not implemented: S_FALSE == no find
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSnapin::CacheHint(
|
|
int, // nStartIndex
|
|
int) // nEndIndex
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSnapin::SortItems(
|
|
int nColumn,
|
|
DWORD, // dwSortOptions
|
|
LPARAM) // lUserParam
|
|
{
|
|
HRESULT hr;
|
|
|
|
LPCWSTR pszHeading;
|
|
BOOL fIndexed = FALSE;
|
|
CComponentDataImpl* pCompData;
|
|
CFolder* pFolder;
|
|
|
|
// if non-virtual, report "we don't allow sort"
|
|
if (!m_bVirtualView)
|
|
goto Ret;
|
|
|
|
pCompData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
if (pCompData == NULL)
|
|
goto Ret;
|
|
|
|
pFolder = GetVirtualFolder();
|
|
if (pFolder == NULL)
|
|
goto Ret;
|
|
|
|
// responding S_OK to this allows ^ and down arrow display
|
|
hr = pCompData->GetDBSchemaEntry(nColumn, &pszHeading, NULL, &fIndexed);
|
|
_JumpIfError(hr, Ret, "GetDBSchemaEntry");
|
|
|
|
if (fIndexed)
|
|
{
|
|
// special case: disallow sort on serial# in failed, pending folders
|
|
// this column has "ignore null" bit set, and sort results in {} set.
|
|
if ((pFolder->GetType() == SERVERFUNC_FAILED_CERTIFICATES) ||
|
|
(pFolder->GetType() == SERVERFUNC_PENDING_CERTIFICATES))
|
|
{
|
|
// if serial number click, act like not indexed -- NO SORT
|
|
if (0 == wcscmp(pszHeading, wszPROPCERTIFICATESERIALNUMBER))
|
|
fIndexed = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
Ret:
|
|
// S_FALSE == no sort
|
|
return fIndexed ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
#define HIDEVERB(__x__) \
|
|
do { \
|
|
m_pConsoleVerb->SetVerbState(__x__, HIDDEN, TRUE); \
|
|
m_pConsoleVerb->SetVerbState(__x__, ENABLED, FALSE); \
|
|
} while(0)
|
|
|
|
#define SHOWVERB(__x__) \
|
|
do { \
|
|
m_pConsoleVerb->SetVerbState(__x__, HIDDEN, FALSE); \
|
|
m_pConsoleVerb->SetVerbState(__x__, ENABLED, TRUE); \
|
|
} while(0)
|
|
|
|
|
|
void CSnapin::HandleStandardVerbs(bool bDeselectAll, LPARAM arg,
|
|
LPDATAOBJECT lpDataObject)
|
|
{
|
|
// You should crack the data object and enable/disable/hide standard
|
|
// commands appropriately. The standard commands are reset everytime you get
|
|
// called. So you must reset them back.
|
|
|
|
|
|
if (m_CustomViewID != VIEW_DEFAULT_LV)
|
|
{
|
|
// UNDONE: When is this executed?
|
|
SHOWVERB(MMC_VERB_REFRESH);
|
|
SHOWVERB(MMC_VERB_PROPERTIES);
|
|
|
|
return;
|
|
}
|
|
|
|
if (!bDeselectAll && lpDataObject == NULL)
|
|
return;
|
|
|
|
WORD bScope = LOWORD(arg);
|
|
WORD bSelect = HIWORD(arg);
|
|
|
|
|
|
//
|
|
// Derive internal, pfolder
|
|
//
|
|
INTERNAL* pInternal = lpDataObject ? ExtractInternalFormat(lpDataObject) : NULL;
|
|
// if scope item, derive parent folder from pInternal.
|
|
// if result item, recall parent folder from saved state
|
|
CFolder* pFolder = (bScope) ? ::GetParentFolder(pInternal) : GetParentFolder(pInternal);
|
|
|
|
//
|
|
// set state appropriately
|
|
//
|
|
if (bDeselectAll || !bSelect)
|
|
{
|
|
// deselection notification
|
|
|
|
// verbs cleared for us, right?
|
|
}
|
|
else if (m_pConsoleVerb && pInternal) // selected
|
|
{
|
|
_MMC_CONSOLE_VERB verbDefault = MMC_VERB_NONE;
|
|
|
|
// unsupported properties
|
|
HIDEVERB(MMC_VERB_OPEN);
|
|
HIDEVERB(MMC_VERB_COPY);
|
|
HIDEVERB(MMC_VERB_PASTE);
|
|
HIDEVERB(MMC_VERB_DELETE);
|
|
HIDEVERB(MMC_VERB_PRINT);
|
|
HIDEVERB(MMC_VERB_RENAME); // could easily be supported, but was removed (bug 217502)
|
|
// MMC_VERB_REFRESH is supported
|
|
// MMC_VERB_PROPERTIES is supported
|
|
|
|
if (pInternal->m_type == CCT_SCOPE)
|
|
{
|
|
if(!pFolder)
|
|
{
|
|
_PrintError2(E_POINTER, "GetParentFolder", E_POINTER);
|
|
return;
|
|
}
|
|
|
|
// selected scope item
|
|
|
|
// Standard functionality support by scope items
|
|
SHOWVERB(MMC_VERB_REFRESH);
|
|
|
|
// Disable properties for static node,
|
|
// enable properties only for server instance, crl
|
|
if ((pInternal->m_cookie != 0) &&
|
|
((SERVER_INSTANCE == pFolder->m_type) ||
|
|
(SERVERFUNC_CRL_PUBLICATION == pFolder->m_type)) )
|
|
{
|
|
SHOWVERB(MMC_VERB_PROPERTIES);
|
|
}
|
|
else
|
|
HIDEVERB(MMC_VERB_PROPERTIES);
|
|
|
|
// default folder verb is open
|
|
verbDefault = MMC_VERB_OPEN;
|
|
}
|
|
else
|
|
{
|
|
// selected result item
|
|
|
|
// Standard functionality supported by result items
|
|
SHOWVERB(MMC_VERB_REFRESH);
|
|
|
|
HIDEVERB(MMC_VERB_PROPERTIES);
|
|
}
|
|
|
|
m_pConsoleVerb->SetDefaultVerb(verbDefault);
|
|
}
|
|
|
|
FREE_DATA(pInternal);
|
|
}
|
|
|
|
void CSnapin::SmartEnableServiceControlButtons()
|
|
{
|
|
BOOL fSvcRunning;
|
|
CComponentDataImpl* pCompData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
if (pCompData)
|
|
{
|
|
|
|
fSvcRunning = pCompData->m_pCertMachine->IsCertSvrServiceRunning();
|
|
if (m_pSvrMgrToolbar1)
|
|
{
|
|
m_pSvrMgrToolbar1->SetButtonState(SvrMgrToolbar1Buttons[ENUM_BUTTON_STARTSVC].item.idCommand, ENABLED, !fSvcRunning);
|
|
m_pSvrMgrToolbar1->SetButtonState(SvrMgrToolbar1Buttons[ENUM_BUTTON_STOPSVC].item.idCommand, ENABLED, fSvcRunning);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void CSnapin::HandleExtToolbars(bool bDeselectAll, LPARAM arg, LPARAM param)
|
|
{
|
|
INTERNAL* pInternal = NULL;
|
|
HRESULT hr;
|
|
|
|
BOOL bScope = (BOOL) LOWORD(arg);
|
|
BOOL bSelect = (BOOL) HIWORD(arg);
|
|
|
|
if (param)
|
|
pInternal = ExtractInternalFormat(reinterpret_cast<LPDATAOBJECT>(param));
|
|
|
|
|
|
// Deselection Notification?
|
|
if (bDeselectAll || bSelect == FALSE)
|
|
return;
|
|
|
|
|
|
ASSERT(bSelect == TRUE);
|
|
bool bFileExBtn = false;
|
|
|
|
|
|
if (pInternal == NULL)
|
|
return;
|
|
|
|
CFolder* pFolder = GetParentFolder(pInternal);
|
|
|
|
if (bScope)
|
|
{
|
|
// special stuff to do at SCOPE level?
|
|
}
|
|
else // result item selected: result or subfolder
|
|
{
|
|
// special stuff to do at RESULTS level
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
bFileExBtn = true;
|
|
|
|
// UNDONE: what to do here with SvrMgrToolbar1Buttons1?
|
|
// For now, do nothing: allow them to remain in same state
|
|
}
|
|
}
|
|
|
|
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
|
|
ASSERT(pData != NULL);
|
|
|
|
if (IsPrimaryImpl() &&
|
|
(IsAllowedStartStop(pFolder, pData->m_pCertMachine)) )
|
|
{
|
|
// Attach the SvrMgrToolbar1 to the window
|
|
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pSvrMgrToolbar1);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
else
|
|
{
|
|
// Detach the SvrMgrToolbar1 to the window
|
|
hr = m_pControlbar->Detach((LPUNKNOWN) m_pSvrMgrToolbar1);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
|
|
SmartEnableServiceControlButtons();
|
|
|
|
FREE_DATA(pInternal);
|
|
}
|
|
|
|
// dropdown menu addition
|
|
void
|
|
CSnapin::HandleExtMenus(
|
|
LPARAM, // arg
|
|
LPARAM) // param
|
|
{
|
|
}
|
|
|
|
|
|
CFolder* CSnapin::GetVirtualFolder()
|
|
{
|
|
ASSERT(m_bVirtualView);
|
|
return m_pCurrentlySelectedScopeFolder;
|
|
}
|
|
|
|
// caller needs to CACloseCertType(hCertType)
|
|
|
|
HRESULT
|
|
CSnapin::FindCertType(
|
|
IN LPCWSTR pcwszCert,
|
|
OUT HCERTTYPE& hCertType)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(NULL==m_hCertTypeList)
|
|
{
|
|
hr = CAEnumCertTypes(
|
|
CT_ENUM_USER_TYPES |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_FLAG_NO_CACHE_LOOKUP,
|
|
&m_hCertTypeList);
|
|
_JumpIfError(hr, error, "CAEnumCertTypes");
|
|
}
|
|
|
|
hr = myFindCertTypeByNameOrOID(
|
|
m_hCertTypeList,
|
|
pcwszCert, // we don't know if this is a name or an OID
|
|
pcwszCert,
|
|
hCertType); // OUT by reference!!!
|
|
_JumpIfError(hr, error, "myFindCertTypeByNameOrOID");
|
|
|
|
if (m_hCertTypeList == hCertType)
|
|
{
|
|
m_hCertTypeList = NULL;
|
|
hr = CAEnumCertTypes(
|
|
CT_ENUM_USER_TYPES |
|
|
CT_ENUM_MACHINE_TYPES,
|
|
&m_hCertTypeList);
|
|
if (S_OK != hr)
|
|
{
|
|
m_hCertTypeList = hCertType;
|
|
hCertType = NULL;
|
|
_JumpError(hr, error, "CAEnumCertTypes");
|
|
}
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|