555 lines
13 KiB
C++
555 lines
13 KiB
C++
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
#include "precomp.h"
|
|
#include <afxcmn.h>
|
|
#include "resource.h"
|
|
#include "SingleViewCtl.h"
|
|
#include "resource.h"
|
|
#include "SingleViewCtl.h"
|
|
#include "DlgDownload.h"
|
|
#include "cv.h"
|
|
#include "utils.h"
|
|
#include "hmmverr.h"
|
|
#include "cvcache.h"
|
|
#include "path.h"
|
|
#include "hmomutil.h"
|
|
|
|
#ifndef _wbemidl_h
|
|
#define _wbemidl_h
|
|
#include <wbemidl.h>
|
|
#endif //_wbemidl_h
|
|
|
|
|
|
|
|
|
|
class CViewInfo
|
|
{
|
|
public:
|
|
CViewInfo();
|
|
~CViewInfo();
|
|
CCustomView* GetView(CSingleViewCtrl* psv, CRect& rcClient, LPCTSTR szObjectPath);
|
|
BOOL CustomViewIsRegistered(CLSID& clsid, DWORD dwFileVersionMS, DWORD dwFileVersionLS);
|
|
CString m_sClass; // The target class of this viewer
|
|
CLSID m_clsid; // The GUID of the class viewer ActiveX control.
|
|
DWORD m_dwFileVersionMS; // The most significant part of the version number.
|
|
DWORD m_dwFileVersionLS; // The least significant part of the version number.
|
|
COleVariant m_varCodebase; // The location of the class viewer ActiveX control.
|
|
CString m_sTitle; // The title that goes into the view selection combo box
|
|
CCustomView* m_pView;
|
|
|
|
private:
|
|
SCODE DownloadCustomView(LPUNKNOWN& punk);
|
|
};
|
|
|
|
|
|
CViewInfo::CViewInfo()
|
|
{
|
|
m_pView = NULL;
|
|
}
|
|
|
|
CViewInfo::~CViewInfo()
|
|
{
|
|
delete m_pView;
|
|
|
|
}
|
|
|
|
|
|
|
|
//***********************************************************************
|
|
// CViewInfo::DownloadCustomView
|
|
//
|
|
// Download the custom view.
|
|
//
|
|
// Parameters:
|
|
// [out] LPUNKNOWN& punk
|
|
// The interface pointer to the custom view is returned here.
|
|
//
|
|
//
|
|
// Returns:
|
|
// SCODE
|
|
// S_OK if the custom view was downloaded and installed successfully,
|
|
// a failure code otherwise.
|
|
//
|
|
//***********************************************************************
|
|
SCODE CViewInfo::DownloadCustomView(LPUNKNOWN& punk)
|
|
{
|
|
SCODE sc;
|
|
|
|
CDlgDownload dlg;
|
|
sc = dlg.DoDownload(
|
|
punk,
|
|
m_clsid,
|
|
m_varCodebase.bstrVal,
|
|
m_dwFileVersionMS,
|
|
m_dwFileVersionLS
|
|
);
|
|
|
|
IWbemLocator *pLocator = 0;
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//************************************************************
|
|
// CViewInfo::CustomViewIsRegistered
|
|
//
|
|
// Parameters:
|
|
// [in] CLSID& clsid
|
|
// The class id for the custom view.
|
|
//
|
|
// [in] DWORD dwFileVersionMS
|
|
// The most significant part of the desired version number.
|
|
// A value of 0xffffffff means any version.
|
|
//
|
|
// [in] DWORD dwFileVersionLS
|
|
// The least significant part of the desired version number.
|
|
// A value of 0xffffffff means any version.
|
|
//
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if an OCX corresponding to the specified class id is
|
|
// registered and the version number of the registered control
|
|
// is the same or greater than the requested version.
|
|
//
|
|
//**************************************************************
|
|
BOOL CViewInfo::CustomViewIsRegistered(CLSID& clsid, DWORD dwFileVersionMS, DWORD dwFileVersionLS)
|
|
{
|
|
// Read the version string from HKEY_CLASSES_ROOT\CLSID\<CLSID>\Version
|
|
//
|
|
// If this key exists, then we know that some version of the custom view is
|
|
// registered, so if the file version is wildcarded, the custom view is installed.
|
|
//
|
|
// If a wildcard is not specified for the file version, then the installed
|
|
// version must be the same or higher than the requested version.
|
|
//
|
|
HKEY hkeyClassesRoot = NULL;
|
|
LONG lResult;
|
|
lResult = RegConnectRegistry(NULL, HKEY_CLASSES_ROOT, &hkeyClassesRoot);
|
|
if (lResult != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct a key path to the version key.
|
|
#ifdef _UNICODE
|
|
TCHAR * pwszClsid = NULL;
|
|
#else
|
|
unsigned char * pwszClsid = NULL;
|
|
#endif
|
|
|
|
RPC_STATUS stat;
|
|
stat = UuidToString(&clsid, &pwszClsid);
|
|
if (stat != RPC_S_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
CString sVersionKey;
|
|
sVersionKey = _T("CLSID\\{");
|
|
sVersionKey += pwszClsid;
|
|
sVersionKey += _T("}");
|
|
sVersionKey += _T("\\Version");
|
|
RpcStringFree(&pwszClsid);
|
|
|
|
|
|
// Open the version key
|
|
HKEY hkeyVersion = NULL;
|
|
lResult = RegOpenKeyEx(
|
|
hkeyClassesRoot,
|
|
(LPCTSTR) sVersionKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyVersion);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
RegCloseKey(hkeyClassesRoot);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Read the version string
|
|
unsigned long lcbValue = 256;
|
|
CString sVersion;
|
|
LPTSTR pszVersion = sVersion.GetBuffer(lcbValue);
|
|
|
|
unsigned long lType;
|
|
lResult = RegQueryValueEx(
|
|
hkeyVersion,
|
|
(LPCTSTR) _T(""),
|
|
NULL,
|
|
&lType,
|
|
(unsigned char*) (void*) pszVersion,
|
|
&lcbValue);
|
|
|
|
|
|
sVersion.ReleaseBuffer();
|
|
RegCloseKey(hkeyVersion);
|
|
RegCloseKey(hkeyClassesRoot);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
// If the requested file version is ANY, then the control is registered
|
|
if (dwFileVersionMS == ~0) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD dwFileVersionMSRegistered;
|
|
DWORD dwFileVersionLSRegistered;
|
|
int nFieldsConverted = 0;
|
|
#ifdef _UNICODE
|
|
nFieldsConverted = swscanf(pszVersion, _T("%ld.%ld"), &dwFileVersionMSRegistered, &dwFileVersionLSRegistered);
|
|
#else
|
|
nFieldsConverted = sscanf(pszVersion, _T("%ld.%ld"), &dwFileVersionMSRegistered, &dwFileVersionLSRegistered);
|
|
#endif
|
|
if (nFieldsConverted != 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (dwFileVersionMS != ~0) {
|
|
if (dwFileVersionMSRegistered < dwFileVersionMS) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwFileVersionLS != ~0) {
|
|
if (dwFileVersionLSRegistered < dwFileVersionLS) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
// CViewInfo::GetView
|
|
//
|
|
// Get a window containing the custom view identified by this CViewInfo object.
|
|
//
|
|
// Parameters:
|
|
// [in] CHmmvCtrl* phmmv
|
|
// Pointer to the view container.
|
|
//
|
|
// [in] CRect& rcClient
|
|
// The client rectangle for the custom view that we're creating.
|
|
//
|
|
// [in] LPCTSTR szObjectPath
|
|
// The object path for the custom view.
|
|
//
|
|
// Returns:
|
|
// CCustomView*
|
|
// A pointer to the custom view if the view could be created, otherwise
|
|
// NULL.
|
|
//
|
|
//*******************************************************************************
|
|
CCustomView* CViewInfo::GetView(CSingleViewCtrl* psv, CRect& rcClient, LPCTSTR szObjectPath)
|
|
{
|
|
// Return the cached view if it exists, but resize it first.
|
|
if (m_pView != NULL) {
|
|
m_pView->MoveWindow(rcClient);
|
|
m_pView->SelectObjectByPath(szObjectPath);
|
|
return m_pView;
|
|
}
|
|
|
|
BOOL bViewIsRegistered;
|
|
bViewIsRegistered = CustomViewIsRegistered(m_clsid, m_dwFileVersionMS, m_dwFileVersionLS);
|
|
|
|
BOOL bDidCreateView = FALSE;
|
|
if (bViewIsRegistered) {
|
|
m_pView = new CCustomView(psv);
|
|
bDidCreateView = m_pView->Create(m_clsid,
|
|
NULL, // Window name
|
|
WS_CHILD | WS_VISIBLE,
|
|
rcClient,
|
|
GenerateWindowID()
|
|
);
|
|
|
|
|
|
if (bDidCreateView) {
|
|
// If the custom view was created successfully, then we are done.
|
|
|
|
m_pView->SelectObjectByPath(szObjectPath);
|
|
return m_pView;
|
|
}
|
|
|
|
|
|
// Control comes here if the custom view was not created.
|
|
// We failed to create the custom view, so we assume that the problem
|
|
// was that it needs to be downloaded from a remote machine. Do
|
|
// the download now.
|
|
|
|
delete m_pView;
|
|
}
|
|
|
|
m_pView = NULL;
|
|
|
|
LPUNKNOWN punkDownload = NULL;
|
|
SCODE sc;
|
|
sc = DownloadCustomView(punkDownload);
|
|
if (FAILED(sc)) {
|
|
if (sc != E_ABORT) {
|
|
// If the download was cancelled, then the user is already aware of the
|
|
// fact that the view is not available. If some other error occurred,
|
|
// give the user a warning.
|
|
HmmvErrorMsg(IDS_ERR_CUSTOM_VIEW_MISSING, S_OK, NULL, NULL, _T(__FILE__), __LINE__);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that the custom view was downloaded, try to create the
|
|
// view again.
|
|
m_pView = new CCustomView(psv);
|
|
bDidCreateView = m_pView->Create(m_clsid,
|
|
NULL, // Window name
|
|
WS_CHILD | WS_VISIBLE,
|
|
rcClient,
|
|
GenerateWindowID()
|
|
);
|
|
|
|
|
|
if (punkDownload) {
|
|
// If the instance pointer is released now, the
|
|
// ReleaseOnDestroy(punkDownload);
|
|
}
|
|
|
|
if (!bDidCreateView) {
|
|
delete m_pView;
|
|
m_pView = NULL;
|
|
HmmvErrorMsg(IDS_ERR_CUSTOM_VIEW_MISSING, S_OK, NULL, NULL, _T(__FILE__), __LINE__);
|
|
|
|
}
|
|
else {
|
|
m_pView->SelectObjectByPath(szObjectPath);
|
|
}
|
|
|
|
return m_pView;
|
|
}
|
|
|
|
|
|
CCustomViewCache::CCustomViewCache(CSingleViewCtrl* psv)
|
|
{
|
|
m_psv = psv;
|
|
}
|
|
|
|
|
|
CCustomViewCache::~CCustomViewCache()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
|
|
void CCustomViewCache::Clear()
|
|
{
|
|
long nViews = (long) m_aViews.GetSize();
|
|
for (long iView = 0; iView < nViews; ++iView) {
|
|
CViewInfo* pViewInfo = (CViewInfo*) m_aViews[iView];
|
|
delete pViewInfo;
|
|
}
|
|
m_aViews.RemoveAll();
|
|
}
|
|
|
|
|
|
SCODE CCustomViewCache::QueryCustomViews()
|
|
{
|
|
CSelection& sel = m_psv->Selection();
|
|
Clear();
|
|
|
|
IWbemServices* phmm = sel.GetHmmServices();
|
|
if (phmm == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (sel.IsClass()) {
|
|
return S_OK;
|
|
}
|
|
|
|
IWbemClassObject* pco = (IWbemClassObject*) sel;
|
|
// If there is no instance, then there can be no viewers.
|
|
if (pco == NULL) {
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
if (sel.IsNewlyCreated()) {
|
|
// No object path is defined yet, so there are no custom views.
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Get the name of the instance's class.
|
|
COleVariant varClassName;
|
|
SCODE sc;
|
|
sc = pco->Get(L"__CLASS", 0, (VARIANT*) &varClassName, NULL, NULL);
|
|
if (sc != S_OK) {
|
|
// __CLASS should always be defined.
|
|
ASSERT(FALSE);
|
|
return sc;
|
|
}
|
|
|
|
// Compose the SQL query
|
|
CString sQuery;
|
|
CString sInstanceClassName;
|
|
sInstanceClassName = varClassName.bstrVal;
|
|
sQuery = sQuery + _T("select * from ClassView where ClassName = \"" + sInstanceClassName + "\"");
|
|
|
|
// Execute the SQL query for custom views
|
|
IEnumWbemClassObject* pEnum;
|
|
CBSTR bsQuery(sQuery);
|
|
CBSTR bsQueryLang(_T("WQL"));
|
|
sc = phmm->ExecQuery((BSTR) bsQueryLang, (BSTR) bsQuery, 0, NULL, &pEnum);
|
|
|
|
if (FAILED(sc)) {
|
|
return sc;
|
|
}
|
|
|
|
|
|
// ConfigureSecurity(pEnum);
|
|
|
|
|
|
// Enumerate the custom views and add an entry for each one to m_aViews
|
|
pEnum->Reset();
|
|
IWbemClassObject* pcoCustomView;
|
|
while (TRUE) {
|
|
unsigned long nReturned;
|
|
pcoCustomView = NULL;
|
|
sc = pEnum->Next(0, 1, &pcoCustomView, &nReturned);
|
|
if (sc != S_OK) {
|
|
break;
|
|
}
|
|
|
|
CViewInfo* pViewInfo = new CViewInfo;
|
|
COleVariant varValue;
|
|
|
|
sc = pcoCustomView->Get(L"classid", 0, varValue, NULL, NULL);
|
|
sc = CLSIDFromString((OLECHAR*) varValue.pbstrVal, &pViewInfo->m_clsid);
|
|
if (sc != S_OK) {
|
|
// The class ID format is not valid, so ignore this view since we
|
|
// can't display it anyway.
|
|
delete pViewInfo;
|
|
continue;
|
|
}
|
|
|
|
int nFieldsConverted = 0;
|
|
sc = pcoCustomView->Get(L"version", 0, varValue, NULL, NULL);
|
|
if (SUCCEEDED(sc) && (varValue.vt!=VT_NULL)) {
|
|
nFieldsConverted = swscanf(varValue.bstrVal, L"%ld.%ld", &pViewInfo->m_dwFileVersionMS, &pViewInfo->m_dwFileVersionLS);
|
|
}
|
|
|
|
if (nFieldsConverted != 2) {
|
|
pViewInfo->m_dwFileVersionMS = (DWORD) (LONG) -1;
|
|
pViewInfo->m_dwFileVersionLS = (DWORD) (LONG) -1;
|
|
}
|
|
|
|
|
|
// !!!CR: Need to catch any failure when reading properties
|
|
sc = pcoCustomView->Get(L"title", 0, varValue, NULL, NULL);
|
|
if (SUCCEEDED(sc)) {
|
|
pViewInfo->m_sTitle = varValue.bstrVal;
|
|
}
|
|
else {
|
|
pViewInfo->m_sTitle.Empty();
|
|
}
|
|
|
|
|
|
sc = pcoCustomView->Get(L"ClassName", 0, varValue, NULL, NULL);
|
|
if (SUCCEEDED(sc)) {
|
|
pViewInfo->m_sClass = varValue.bstrVal;
|
|
}
|
|
else {
|
|
pViewInfo->m_sClass.Empty();
|
|
}
|
|
|
|
|
|
sc = pcoCustomView->Get(L"codebase", 0, pViewInfo->m_varCodebase, NULL, NULL);
|
|
if (FAILED(sc)) {
|
|
pViewInfo->m_varCodebase = "";
|
|
}
|
|
|
|
|
|
pcoCustomView->Release();
|
|
|
|
// Add this view info to the cache.
|
|
m_aViews.Add(pViewInfo);
|
|
|
|
}
|
|
pEnum->Release();
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LPCTSTR CCustomViewCache::GetViewTitle(long lPosition)
|
|
{
|
|
if (lPosition < 0) {
|
|
return _T("");
|
|
}
|
|
|
|
long nViews = (long) m_aViews.GetSize();
|
|
if (lPosition >= nViews) {
|
|
return _T("");
|
|
}
|
|
|
|
|
|
CViewInfo* pViewInfo = (CViewInfo*) m_aViews[lPosition];
|
|
return (LPCTSTR) pViewInfo->m_sTitle;
|
|
}
|
|
|
|
|
|
|
|
SCODE CCustomViewCache::GetView(CCustomView** ppView, long lPosition)
|
|
{
|
|
if (lPosition < 0) {
|
|
*ppView = NULL;
|
|
return E_FAIL;
|
|
}
|
|
long nViews = (long) m_aViews.GetSize();
|
|
if (lPosition >= nViews) {
|
|
*ppView = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
CRect rcView;
|
|
m_psv->GetClientRect(rcView);
|
|
CSelection& sel = m_psv->Selection();
|
|
LPCTSTR szObjectPath = (LPCTSTR) sel;
|
|
CViewInfo* pInfo = (CViewInfo*) m_aViews[lPosition];
|
|
|
|
CCustomView* pView = pInfo->GetView(m_psv, rcView, szObjectPath);
|
|
*ppView = pView;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
SCODE CCustomViewCache::FindCustomView(CLSID& clsid, long* plView)
|
|
{
|
|
SCODE sc = E_FAIL;
|
|
long nViews = (long) m_aViews.GetSize();
|
|
for (long lView = 0; lView < nViews; ++lView) {
|
|
CViewInfo* pInfo = (CViewInfo*) m_aViews[lView];
|
|
if (pInfo->m_clsid == clsid) {
|
|
*plView = lView;
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
return sc;
|
|
}
|
|
|