Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

781 lines
21 KiB

// Copyright (c) 1997-2002 Microsoft Corporation
#include "precomp.h"
#ifdef EXT_DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include "DepPage.h"
// avoid some warnings.
#undef HDS_HORZ
#undef HDS_BUTTONS
#undef HDS_HIDDEN
#include "resource.h"
#include <stdlib.h>
#include <TCHAR.h>
#include "..\Common\util.h"
#include <regstr.h>
#include "..\common\ConnectThread.h"
#include "..\MMFUtil\MsgDlg.h"
#include "winuser.h"
BOOL AfxIsValidAddress(const void* lp,
UINT nBytes,
BOOL bReadWrite)
{
// simple version using Win-32 APIs for pointer validation.
return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
(!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
}
const wchar_t *CFServiceName = L"FILEMGMT_SNAPIN_SERVICE_NAME";
const wchar_t *CFServiceDisplayName = L"FILEMGMT_SNAPIN_SERVICE_DISPLAYNAME";
//--------------------------------------------------------------
DependencyPage::DependencyPage(WbemConnectThread *pConnectThread,
IDataObject *pDataObject,
long lNotifyHandle, bool bDeleteHandle, TCHAR* pTitle)
: PageHelper(pConnectThread),
CSnapInPropertyPageImpl<DependencyPage> (pTitle),
m_lNotifyHandle(lNotifyHandle),
m_bDeleteHandle(bDeleteHandle),
m_qLang("WQL"),
m_NameProp("Name"),
m_DispNameProp("DisplayName")
{
m_servIcon = 0;
m_sysDriverIcon = 0;
m_emptyIcon = 0;
m_groupIcon = 0;
ATLTRACE(L"dependency Page CTOR\n");
m_queryFormat = new TCHAR[QUERY_SIZE];
m_queryTemp = new TCHAR[QUERY_SIZE];
Extract(pDataObject, L"FILEMGMT_SNAPIN_SERVICE_NAME", m_ServiceName);
Extract(pDataObject, L"FILEMGMT_SNAPIN_SERVICE_DISPLAYNAME", m_ServiceDispName);
}
//--------------------------------------------------------------
DependencyPage::~DependencyPage()
{
ATLTRACE(L"dependency Page DTOR\n");
delete[] m_queryFormat;
delete[] m_queryTemp;
}
//--------------------------------------------------------------
void DependencyPage::BuildQuery(TV_ITEM *fmNode,
QUERY_TYPE queryType,
bool depends,
bstr_t &query)
{
// clean the working space.
memset(m_queryFormat, 0, QUERY_SIZE * sizeof(TCHAR));
memset(m_queryTemp, 0, QUERY_SIZE * sizeof(TCHAR));
// here's the WQL syntax format.
switch(queryType)
{
case DepService:
_tcscpy(m_queryFormat,
_T("Associators of {Win32_BaseService.Name=\"%s\"} where Role=%s AssocClass=Win32_DependentService"));
// build the query for this level.
_sntprintf(m_queryTemp, QUERY_SIZE- 1, m_queryFormat,
(LPCTSTR)((ITEMEXTRA *)fmNode->lParam)->realName,
(depends ? _T("Dependent") : _T("Antecedent")));
break;
case DepGroup:
_tcscpy(m_queryFormat,
_T("Associators of {Win32_BaseService.Name=\"%s\"} where ResultClass=Win32_LoadOrderGroup Role=%s AssocClass=Win32_LoadOrderGroupServiceDependencies"));
// build the query for this level.
_sntprintf(m_queryTemp, QUERY_SIZE- 1, m_queryFormat,
(LPCTSTR)((ITEMEXTRA *)fmNode->lParam)->realName,
(depends ? _T("Dependent") : _T("Antecedent")));
break;
case GroupMember:
_tcscpy(m_queryFormat,
_T("Associators of {Win32_LoadOrderGroup.Name=\"%s\"} where Role=GroupComponent AssocClass=Win32_LoadOrderGroupServiceMembers"));
// L"Associators of {Win32_LoadOrderGroup.Name=\"%s\"} where ResultClass=Win32_Service Role=GroupComponent AssocClass=Win32_LoadOrderGroupServiceMembers");
// build the query for this level.
_sntprintf(m_queryTemp, QUERY_SIZE- 1, m_queryFormat,
(LPCTSTR)((ITEMEXTRA *)fmNode->lParam)->realName);
break;
} // endswitch
m_queryTemp[QUERY_SIZE - 1] = 0;
// cast to bstr_t and return.
query = m_queryTemp;
}
//--------------------------------------------------------------
void DependencyPage::LoadLeaves(HWND hTree, TV_ITEM *fmNode, bool depends )
{
bstr_t query;
NODE_TYPE nodeType = ((ITEMEXTRA *)fmNode->lParam)->nodeType;
bool foundIt = false;
// HourGlass(true);
switch(nodeType)
{
case ServiceNode:
// NOTE: services can depend on groups but not the
// other way around.
if(depends)
{
//load groups.
BuildQuery(fmNode, DepGroup, depends, query);
foundIt = Load(hTree, fmNode, query, GroupNode);
}
// load services.
BuildQuery(fmNode, DepService, depends, query);
foundIt |= Load(hTree, fmNode, query, ServiceNode);
break;
case GroupNode:
// NOTE: 'depends' doesn't matter in this case.
// load group members.
BuildQuery(fmNode, GroupMember, depends, query);
foundIt = Load(hTree, fmNode, query, ServiceNode);
break;
}//endswitch
//TODO: Decide opn what to do for this
// HourGlass(false);
if(!foundIt)
{
NothingMore(hTree, fmNode);
if(depends)
{
if(fmNode->hItem == TVI_ROOT)
{
::EnableWindow(GetDlgItem(IDC_DEPENDS_LBL), FALSE);
}
}
else
{
if(fmNode->hItem == TVI_ROOT)
{
::EnableWindow(GetDlgItem(IDC_NEEDED_LBL), FALSE);
}
}
}
}
//--------------------------------------------------------------
// READ: In 'hTree', run 'query' and make the children
// 'childType' nodes under 'fmNode'.
bool DependencyPage::Load(HWND hTree, TV_ITEM *fmNode, bstr_t query,
NODE_TYPE childType)
{
HRESULT hRes;
variant_t pRealName, pDispName;
ULONG uReturned;
IWbemClassObject *pOther = NULL;
IEnumWbemClassObject *pEnumOther = NULL;
TV_INSERTSTRUCT leaf;
leaf.hInsertAfter = TVI_SORT;
leaf.hParent = fmNode->hItem;
bool foundOne = false;
ATLTRACE(L"query started\n");
hRes = m_WbemServices.ExecQuery(m_qLang, query,
WBEM_FLAG_RETURN_IMMEDIATELY |
WBEM_FLAG_FORWARD_ONLY,
&pEnumOther);
//-------------------
// query for all related services or groups.
if(hRes == S_OK)
{
ATLTRACE(L"query worked %x\n", hRes);
//-------------------
// enumerate through services.
while(SUCCEEDED(hRes = pEnumOther->Next(500, 1, &pOther, &uReturned)))
{
if(hRes == WBEM_S_TIMEDOUT)
continue;
if(uReturned != 1)
{
ATLTRACE(L"uReturned failed %x: %s \n", hRes, query);
break;
}
foundOne = true;
//-------------------
// get the node's name(s).
switch(childType)
{
case ServiceNode:
hRes = pOther->Get(m_DispNameProp, 0, &pDispName, NULL, NULL);
hRes = pOther->Get(m_NameProp, 0, &pRealName, NULL, NULL);
if(SUCCEEDED(hRes))
{
hRes = pOther->Get(m_DispNameProp, 0, &pDispName, NULL, NULL);
}
break;
case GroupNode:
hRes = pOther->Get(m_NameProp, 0, &pRealName, NULL, NULL);
if(SUCCEEDED(hRes))
{
pDispName = pRealName;
}
break;
}// endswitch
// got the properties ok?
if(SUCCEEDED(hRes))
{
// add the leaf.
leaf.item.mask = TVIF_TEXT | TVIF_PARAM |
TVIF_CHILDREN |TVIF_IMAGE |TVIF_SELECTEDIMAGE;
leaf.item.hItem = 0;
leaf.item.state = 0;
leaf.item.stateMask = 0;
if(pDispName.vt == VT_BSTR)
{
leaf.item.pszText = CloneString((bstr_t)pDispName);
}
else
{
leaf.item.pszText = CloneString((bstr_t)pRealName);
}
leaf.item.cchTextMax = ARRAYSIZE(leaf.item.pszText);
TCHAR pszCreationClassName[20];
_tcscpy(pszCreationClassName,_T("CreationClassName"));
variant_t pCreationName;
_bstr_t strCreationClassName;
// set the icon based on 'childType'
switch(childType)
{
case ServiceNode:
//Here we will have to change the icon depending on whether it is a win32_service or
//Win32_SystemDriver
pOther->Get(pszCreationClassName, 0, &pCreationName, NULL, NULL);
strCreationClassName = pCreationName.bstrVal;
if(_tcsicmp(strCreationClassName,_T("Win32_Service")) == 0)
{
leaf.item.iImage = m_servIcon;
leaf.item.iSelectedImage = m_servIcon;
}
else
{
leaf.item.iImage = m_sysDriverIcon;
leaf.item.iSelectedImage = m_sysDriverIcon;
}
break;
case GroupNode:
leaf.item.iImage = m_groupIcon;
leaf.item.iSelectedImage = m_groupIcon;
break;
} // endswitch
// turn on the '+' sign.
leaf.item.cChildren = 1;
// set internal data.
ITEMEXTRA *extra = new ITEMEXTRA;
if (extra != NULL)
{
extra->loaded = false;
extra->nodeType = childType;
// true name.
extra->realName = CloneString((bstr_t)pRealName);
leaf.item.lParam = (LPARAM) extra;
TreeView_InsertItem(hTree, &leaf);
// if there is a parent...
if(fmNode->hItem != TVI_ROOT)
{
// indicate that the parent's children have been
// loaded. This helps optimize for collapsing/re-
// expanding.
fmNode->mask = TVIF_PARAM | TVIF_HANDLE;
((ITEMEXTRA *)fmNode->lParam)->loaded = true;
TreeView_SetItem(hTree, fmNode);
}
}
} // endif Get() user name
// done with the ClassObject
if (pOther)
{
pOther->Release();
pOther = NULL;
}
} //endwhile Next()
ATLTRACE(L"while %x: %s \n", hRes, (wchar_t *)query);
// release the enumerator.
if(pEnumOther)
{
pEnumOther->Release();
pEnumOther = NULL;
}
}
else
{
ATLTRACE(L"query failed %x: %s \n", hRes, query);
} //endif ExecQuery()
// if nothing found...
return foundOne;
}
//---------------------------------------------------
void DependencyPage::NothingMore(HWND hTree, TV_ITEM *fmNode)
{
TV_INSERTSTRUCT leaf;
leaf.hInsertAfter = TVI_SORT;
leaf.hParent = fmNode->hItem;
// and its the root...
if(fmNode->hItem == TVI_ROOT)
{
// indicate an 'empty' tree.
leaf.item.pszText = new TCHAR[100];
if( NULL == leaf.item.pszText ) return;
leaf.item.cchTextMax = 100;
::LoadString(HINST_THISDLL, IDS_NO_DEPS,
leaf.item.pszText,
leaf.item.cchTextMax);
leaf.item.mask = TVIF_TEXT | TVIF_PARAM |
TVIF_CHILDREN | TVIF_IMAGE |
TVIF_SELECTEDIMAGE;
leaf.item.hItem = 0;
leaf.item.state = 0;
leaf.item.stateMask = 0;
leaf.item.iImage = m_emptyIcon;
leaf.item.iSelectedImage = m_emptyIcon;
leaf.item.cChildren = 0;
ITEMEXTRA *extra = new ITEMEXTRA;
if(extra == NULL)
{
delete[] leaf.item.pszText;
return;
}
extra->loaded = false;
extra->nodeType = ServiceNode;
extra->realName = NULL; // to be safe during cleanup.
leaf.item.lParam = (LPARAM) extra;
TreeView_InsertItem(hTree, &leaf);
::EnableWindow(hTree, FALSE);
delete[] leaf.item.pszText;
}
else // not the root.
{
// Cant drill down anymore.
// Turn off the [+] symbol.
fmNode->mask = TVIF_CHILDREN | TVIF_HANDLE;
fmNode->cChildren = 0;
TreeView_SetItem(hTree, fmNode);
}
}
//--------------------------------------------------------------
void DependencyPage::TwoLines(UINT uID, LPCTSTR staticString, LPCTSTR inStr, LPTSTR outStr,bool bStaticFirst)
{
HWND ctl = ::GetDlgItem(m_hWnd, uID);
HDC hDC = ::GetDC(ctl);
//THIS IS A HACK. I COULD NOT CALCULATE THE ACTUAL WIDTH OF THE CONTROL
//IN LOGICAL UNITS. SO AS OF NOW, CALCULATED MANUALLY AND HARDCODING IT.
int ctlWidth = 509;
TCHAR strTemp[1024];
TCHAR *strCurr;
int lenstrTemp;
SIZE sizeTemp;
int nFit = 0;
//First we will try whether the whole string fits in the space
if(bStaticFirst == true)
{
_sntprintf(strTemp, 1023, _T("%s \"%s\""),staticString,inStr);
}
else
{
_sntprintf(strTemp, 1023, _T("\"%s\" %s"),inStr,staticString);
}
strTemp[1023] = 0;
strCurr = strTemp;
lenstrTemp = lstrlen(strTemp);
GetTextExtentExPoint(hDC,strTemp,lenstrTemp,ctlWidth,&nFit,NULL,&sizeTemp);
if(lenstrTemp <= nFit)
{
//The whole string will fit in a line. So we will all a \r\n in the beginning
_sntprintf(outStr, 1023, _T("\r\n%s"),strTemp);
outStr[1023] = 0;
return;
}
//Now we will try if the whole string atleast fits in 2 lines.
strCurr += nFit;
int nFit1;
lenstrTemp = lstrlen(strCurr);
GetTextExtentExPoint(hDC,strCurr,lenstrTemp,ctlWidth,&nFit1,NULL,&sizeTemp);
if(lenstrTemp <= nFit1)
{
//The whole string will fit in 2 lines. So we will all a \r\n in the end of the first line
TCHAR strTemp1[1024];
_tcsncpy(strTemp1,strTemp,nFit);
strTemp1[nFit] = _T('\0');
_sntprintf(outStr,1023,_T("%s\r\n%s"),strTemp1,strCurr);
outStr[1023] = 0;
return;
}
//NOW since it won't fit in 2 lines, we will have to do some calculations and
//add a "..." to the end of the instr so that it will fit in 2 lines.
//If the static string is in the from, then we can easily do it.
TCHAR strLast[5];
_tcscpy(strLast,_T("...\""));
int sizeLast = lstrlen(strLast);
SIZE sz1;
GetTextExtentPoint32(hDC,strLast,sizeLast,&sz1);
TCHAR strTemp1[1024];
_tcsncpy(strTemp1,strTemp,nFit);
strTemp1[nFit] = _T('\0');
if(bStaticFirst == true)
{
TCHAR strTemp2[10];
//Now take characters from the end of the array and match it until the
//width needed to print is greater than the "..."" string
bool bFit = false;
int nStart = nFit1 - 4;
int nStart1;
SIZE sz2;
while(bFit == false)
{
nStart1 = nStart;
for(int i=0; i < nFit1 - nStart; i++)
{
strTemp2[i] = strCurr[nStart1];
nStart1 ++;
}
strTemp2[i] = _T('\0');
GetTextExtentPoint32(hDC,strTemp2,nFit1 - nStart,&sz2);
if(sz2.cx < sz1.cx)
{
nStart --;
}
else
{
break;
}
}
strCurr[nStart] = _T('\0');
_sntprintf(outStr,1023,_T("%s\r\n%s%s"),strTemp1,strCurr,strLast);
outStr[1023] = 0;
return;
}
else
{
//Now we will have to add strLast to the end of trimmed string.
//Since it will be the same in the first line, we will first calculate fit1 again.
SIZE szFinal;
TCHAR strFinal[1024];
_sntprintf(strFinal,1023,_T("%s %s"),strLast,staticString);
strFinal[1023] = 0;
GetTextExtentPoint32(hDC,strFinal,lstrlen(strFinal),&szFinal);
//Now subtract szFinal from the ctlWidth and calculate the number of characters
//that will fit in to that space
GetTextExtentExPoint(hDC,strCurr,lstrlen(strCurr),ctlWidth - szFinal.cx ,&nFit1,NULL,&sizeTemp);
strCurr[nFit1-1] = _T('\0');
_sntprintf(outStr,1023,_T("%s\r\n%s%s"),strTemp1,strCurr,strFinal);
outStr[1023] = 0;
return;
}
}
//--------------------------------------------------------------
LRESULT DependencyPage::OnInit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_hDlg = m_hWnd;
//TODO: Check this out
if(m_pgConnectThread)
{
m_pgConnectThread->SendPtr(m_hWnd);
}
TCHAR szBuffer1[100] = {0}, szBuffer2[256] = {0};
SetDlgItemText(IDC_DEPENDS_SRVC, (wchar_t *)m_ServiceDispName);
// set the nice bitmap.
SetClearBitmap(GetDlgItem(IDC_PICT ), MAKEINTRESOURCE( IDB_SERVICE ), 0);
// create an empty imagelist.
HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR8|ILC_MASK, 3, 0);
// add an icon
m_servIcon = ImageList_AddIcon(hImageList,
LoadIcon(HINST_THISDLL,
MAKEINTRESOURCE(IDI_SERVICE)));
m_sysDriverIcon = ImageList_AddIcon(hImageList,
LoadIcon(HINST_THISDLL,
MAKEINTRESOURCE(IDI_SYSTEMDRIVER)));
m_emptyIcon = ImageList_AddIcon(hImageList,
LoadIcon(NULL,
MAKEINTRESOURCE(IDI_INFORMATION)));
m_groupIcon = ImageList_AddIcon(hImageList,
LoadIcon(HINST_THISDLL,
MAKEINTRESOURCE(IDI_SERVGROUP)));
// sent it to the trees.
TreeView_SetImageList(GetDlgItem(IDC_DEPENDS_TREE),
hImageList,
TVSIL_NORMAL);
TreeView_SetImageList(GetDlgItem(IDC_NEEDED_TREE),
hImageList,
TVSIL_NORMAL);
InvalidateRect(NULL);
UpdateWindow();
ATLTRACE(L"UpdateWindow() fm Init\n");
// can we get data yet?
::PostMessage(m_hDlg, WM_ENUM_NOW, 0, 0);
HourGlass(true);
return S_OK;
}
//--------------------------------------------------------------
void DependencyPage::LoadTrees(void)
{
ATLTRACE(L"checking service\n");
// did that background connection thread work yet?
if(ServiceIsReady(IDS_DISPLAY_NAME, IDS_CONNECTING, IDS_BAD_CONNECT))
{
//Now we will check if there is already some nodes.
//If it is, then it means that we don't have to enumerate it again.
//This normally happens in the first time when we connect to a remote machine
/* //We will clear the nodes if it already exists
TreeView_DeleteAllItems(GetDlgItem(IDC_DEPENDS_TREE));
TreeView_DeleteAllItems(GetDlgItem(IDC_NEEDED_TREE));
*/
if(TreeView_GetCount(GetDlgItem(IDC_DEPENDS_TREE)) == 0)
{
HourGlass(true);
TV_ITEM root;
ITEMEXTRA *extra = new ITEMEXTRA;
if(extra == NULL)
return;
root.hItem = TVI_ROOT; // I'm making a root.
root.pszText = m_ServiceDispName;
extra->realName = CloneString(m_ServiceName);
extra->loaded = false;
extra->nodeType = ServiceNode;
root.lParam = (LPARAM)extra;
InvalidateRect(NULL);
UpdateWindow();
// load the first levels.
LoadLeaves(GetDlgItem(IDC_DEPENDS_TREE),
&root, true);
LoadLeaves(GetDlgItem(IDC_NEEDED_TREE),
&root, false);
SetFocus();
HourGlass(false);
}
}
}
//--------------------------------------------------------------
BOOL DependencyPage::OnApply()
{
::SetWindowLongPtr(m_hDlg, DWLP_USER, 0);
return TRUE;
}
//--------------------------------------------------------------
BOOL DependencyPage::OnKillActive()
{
//SetWindowLong(DWL_MSGRESULT, 0);
return TRUE;
}
//--------------------------------------------------------------
LRESULT DependencyPage::OnEnumNow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if(lParam)
{
IStream *pStream = (IStream *)lParam;
IWbemServices *pServices = 0;
HRESULT hr = CoGetInterfaceAndReleaseStream(pStream,
IID_IWbemServices,
(void**)&pServices);
if(SUCCEEDED(hr))
{
SetWbemService(pServices);
pServices->Release();
}
LoadTrees(); //calls ServiceIsReady() itself.
}
else if(FAILED(m_pgConnectThread->m_hr))
{
DisplayUserMessage(m_hDlg, HINST_THISDLL,
IDS_DISPLAY_NAME, BASED_ON_SRC,
ConnectServer,
m_pgConnectThread->m_hr,
MB_ICONSTOP);
}
else
{
m_pgConnectThread->NotifyWhenDone(&m_hDlg);
}
return S_OK;
}
//--------------------------------------------------------------
LRESULT DependencyPage::OnItemExpanding(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
// which node?
NM_TREEVIEW *notice = (NM_TREEVIEW *)pnmh;
// we're expanding, not collapsing...
if(notice->action == TVE_EXPAND)
{
// which tree?
HWND treeHWND = GetDlgItem(idCtrl);
TV_ITEM item;
item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN |TVIF_IMAGE;
item.pszText = new TCHAR[200];
item.cchTextMax = 200;
item.hItem = notice->itemNew.hItem;
TreeView_GetItem(treeHWND, &item);
// if we've never tried...
if(((ITEMEXTRA *)item.lParam)->loaded == false)
{
// NOTE: really cant get here if its not ready
// but better safe than sorry.
if(ServiceIsReady(IDS_DISPLAY_NAME, IDS_CONNECTING, IDS_BAD_CONNECT))
{
// load it.
LoadLeaves(treeHWND, &item, (idCtrl == IDC_DEPENDS_TREE));
}
}
delete[] item.pszText;
} //end action
return S_OK;
}
//-------------------------------------------------------------------------------
LRESULT DependencyPage::OnDeleteItem(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
NM_TREEVIEW *notice = (NM_TREEVIEW *)pnmh;
delete[] (TCHAR *)((ITEMEXTRA *)notice->itemOld.lParam)->realName;
delete (ITEMEXTRA *)notice->itemOld.lParam;
return S_OK;
}
//-------------------------------------------------------------------------------
DWORD aDepHelpIds[] = {
IDC_PICT, -1,
IDC_DESC, -1,
IDC_DEPENDS_LBL, (985), // dependsOn
IDC_DEPENDS_TREE, (985), // dependsOn
IDC_NEEDED_LBL, (988), // neededBy
IDC_NEEDED_TREE, (988), // neededBy
0, 0
};
LRESULT DependencyPage::OnF1Help(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
::WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
L"filemgmt.hlp",
HELP_WM_HELP,
(ULONG_PTR)(LPSTR)aDepHelpIds);
return S_OK;
}
//-------------------------------------------------------------------------------
LRESULT DependencyPage::OnContextHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
::WinHelp((HWND)wParam,
L"filemgmt.hlp",
HELP_CONTEXTMENU,
(ULONG_PTR)(LPSTR)aDepHelpIds);
return S_OK;
}