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.
4435 lines
138 KiB
4435 lines
138 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 1998.
|
|
//
|
|
// File: browser.cpp
|
|
//
|
|
// Contents: implementation of the general GPO browser pane
|
|
//
|
|
// Classes: CBrowserPP
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 04-30-1998 stevebl Created
|
|
//
|
|
// Notes: This is the pane that behaves much like the standard file
|
|
// open dialog. The class is used for all panes that have this
|
|
// format since they share so much functionality. The
|
|
// dwPageType parameter passed to CBrowserPP::Initialize is
|
|
// used to distinguish between the different flavors.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "main.h"
|
|
#include "browser.h"
|
|
#include "commctrl.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
//
|
|
// Help ids
|
|
//
|
|
|
|
DWORD aBrowserDomainHelpIds[] =
|
|
{
|
|
IDC_COMBO1, IDH_BROWSER_LOOKIN,
|
|
IDC_LIST1, IDH_BROWSER_DOMAINGPO,
|
|
IDC_DESCRIPTION, IDH_NOCONTEXTHELP,
|
|
|
|
0, 0
|
|
};
|
|
|
|
DWORD aBrowserSiteHelpIds[] =
|
|
{
|
|
IDC_COMBO1, IDH_BROWSER_SITELIST,
|
|
IDC_LIST1, IDH_BROWSER_GPOLIST,
|
|
IDC_DESCRIPTION, IDH_NOCONTEXTHELP,
|
|
|
|
0, 0
|
|
};
|
|
|
|
DWORD aBrowserAllHelpIds[] =
|
|
{
|
|
IDC_COMBO1, IDH_BROWSER_DOMAINLIST,
|
|
IDC_LIST1, IDH_BROWSER_FULLGPOLIST,
|
|
IDC_DESCRIPTION, IDH_NOCONTEXTHELP,
|
|
|
|
0, 0
|
|
};
|
|
|
|
|
|
CBrowserPP::CBrowserPP()
|
|
{
|
|
m_ppActive = NULL;
|
|
m_pGBI = NULL;
|
|
m_pPrevSel = NULL;
|
|
m_szServerName = NULL;
|
|
m_szDomainName = NULL;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: CopyAsFriendlyName
|
|
//
|
|
// Synopsis: Copies a LDAP path converting it to a friendly name by
|
|
// removing the "LDAP://" and "XX=" and converting "," to "."
|
|
// and removing a server name (if any)
|
|
//
|
|
// Arguments: [lpDest] - destination buffer
|
|
// [lpSrc] - source buffer
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// History: 5-07-1998 stevebl Created
|
|
//
|
|
// Notes: The destination buffer should be as large as the source
|
|
// buffer to ensure safe completion. lpDest and lpSrc may both
|
|
// point to the same buffer.
|
|
//
|
|
// As an example, this routine would convert the following path:
|
|
// LDAP://DC=abcd,DC=efg
|
|
// into this:
|
|
// abcd.efg
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CopyAsFriendlyName(WCHAR * lpDest, WCHAR * lpSrc)
|
|
{
|
|
LPOLESTR lpProvider = L"LDAP://";
|
|
DWORD dwStrLen = wcslen(lpProvider);
|
|
|
|
// lpStopChecking marks the last spot where we can safely
|
|
// look ahead 2 spaces for an '=' character. Anything past
|
|
// this and we are looking in memory we don't own.
|
|
OLECHAR * lpStopChecking = (wcslen(lpSrc) - 2) + lpSrc;
|
|
|
|
//
|
|
// Skip the LDAP:// if found
|
|
//
|
|
|
|
if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_STOP_ON_NULL,
|
|
lpProvider, dwStrLen, lpSrc, dwStrLen) == CSTR_EQUAL)
|
|
{
|
|
lpSrc += dwStrLen;
|
|
}
|
|
|
|
//
|
|
// Remove server name (if any)
|
|
//
|
|
if (lpSrc < lpStopChecking)
|
|
{
|
|
if (*(lpSrc+2) != L'=')
|
|
{
|
|
// look for a '/' character marking the end of a server name
|
|
while (*lpSrc)
|
|
{
|
|
if (*lpSrc == L'/')
|
|
{
|
|
lpSrc++;
|
|
break;
|
|
}
|
|
lpSrc++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Parse through the name replacing all the XX= with .
|
|
//
|
|
|
|
while (*lpSrc)
|
|
{
|
|
if (lpSrc < lpStopChecking)
|
|
{
|
|
if (*(lpSrc+2) == L'=')
|
|
{
|
|
lpSrc += 3;
|
|
}
|
|
}
|
|
|
|
while (*lpSrc && (*lpSrc != L','))
|
|
{
|
|
// remove escape sequences
|
|
if (*lpSrc == L'\\')
|
|
{
|
|
lpSrc++;
|
|
// special cases
|
|
// make sure that '\\x' becomes '\x'
|
|
if (*lpSrc == L'\\')
|
|
{
|
|
*lpDest++ = *lpSrc++;
|
|
}
|
|
// make sure that '\0D' becomes '\r'
|
|
else if (*lpSrc == L'0' && *(lpSrc+1) == L'D')
|
|
{
|
|
*lpDest++ = L'\r';
|
|
lpSrc += 2;
|
|
}
|
|
// make sure that '\0A' becomes '\n'
|
|
else if (*lpSrc == L'0' && *(lpSrc+1) == L'A')
|
|
{
|
|
*lpDest++ = L'\n';
|
|
lpSrc += 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*lpDest++ = *lpSrc++;
|
|
}
|
|
}
|
|
|
|
if (*lpSrc == L',')
|
|
{
|
|
*lpDest++ = L'.';
|
|
lpSrc++;
|
|
}
|
|
}
|
|
|
|
*lpDest = L'\0';
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::Initialize
|
|
//
|
|
// Synopsis: Initializes the property page.
|
|
//
|
|
// Arguments: [dwPageType] - used to identify which page this is. (See
|
|
// notes.)
|
|
// [pGBI] - pointer to the browse info structure passed
|
|
// by caller
|
|
// [ppActive] - pointer to a common variable that remembers
|
|
// which object was last given the focus.
|
|
// Needed because only the page with the focus
|
|
// is allowed to return data to the caller when
|
|
// the property sheet is dismissed.
|
|
//
|
|
// Returns: Handle to the newly created property page.
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// History: 04-30-1998 stevebl Created
|
|
//
|
|
// Notes: This class implements the following property pages:
|
|
// PAGETYPE_DOMAINS - GPO's linked to domains
|
|
// PAGETYPE_SITES - GPO's linked to sites
|
|
// PAGETYPE_ALL - All GPO's in a selected
|
|
//
|
|
// PAGETYPE_COMPUTERS is implemented by CCompsPP since it
|
|
// behaves so differently.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HPROPSHEETPAGE CBrowserPP::Initialize(DWORD dwPageType, LPGPOBROWSEINFO pGBI, void * * ppActive)
|
|
{
|
|
m_ppActive = ppActive;
|
|
m_dwPageType = dwPageType;
|
|
m_pGBI = pGBI;
|
|
|
|
if (m_pGBI->lpInitialOU)
|
|
{
|
|
//
|
|
// Get the server name
|
|
//
|
|
|
|
m_szServerName = ExtractServerName(m_pGBI->lpInitialOU);
|
|
DebugMsg((DM_VERBOSE, TEXT("CBrowserPP::Initialize extracted server name: %s"), m_szServerName));
|
|
|
|
//
|
|
// Get the friendly domain name
|
|
//
|
|
|
|
LPOLESTR pszDomain = GetDomainFromLDAPPath(m_pGBI->lpInitialOU);
|
|
|
|
//
|
|
// Convert LDAP to dot (DN) style
|
|
//
|
|
|
|
if (pszDomain)
|
|
{
|
|
ConvertToDotStyle (pszDomain, &m_szDomainName);
|
|
DebugMsg((DM_VERBOSE, TEXT("CBrowserPP::Initialize extracted domain name: %s"), m_szDomainName));
|
|
delete [] pszDomain;
|
|
}
|
|
}
|
|
|
|
DWORD dwTitle;
|
|
switch (dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
dwTitle = IDS_DOMAINS;
|
|
break;
|
|
case PAGETYPE_SITES:
|
|
dwTitle = IDS_SITES;
|
|
break;
|
|
case PAGETYPE_ALL:
|
|
default:
|
|
dwTitle = IDS_ALL;
|
|
break;
|
|
}
|
|
LoadString(g_hInstance, dwTitle, m_szTitle, sizeof(m_szTitle) / sizeof(WCHAR));
|
|
|
|
PROPSHEETPAGE psp;
|
|
memset(&psp, 0, sizeof(psp));
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags = PSP_USETITLE;
|
|
psp.pszTitle = m_szTitle;
|
|
psp.hInstance = g_hInstance;
|
|
psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_GPOBROWSER);
|
|
return CreatePropertySheetPage(&psp);
|
|
}
|
|
|
|
CBrowserPP::~CBrowserPP()
|
|
{
|
|
if (m_szServerName)
|
|
{
|
|
LocalFree(m_szServerName);
|
|
}
|
|
if (m_szDomainName)
|
|
{
|
|
LocalFree(m_szDomainName);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBrowserPP message handlers
|
|
|
|
INT CBrowserPP::AddElement(MYLISTEL * pel, INT index)
|
|
{
|
|
LV_ITEM item;
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
|
|
if (-1 == index)
|
|
{
|
|
index = ListView_GetItemCount(m_hList);
|
|
}
|
|
item.iItem = index;
|
|
item.pszText = pel->szName;
|
|
|
|
if (pel->nType == ITEMTYPE_FOREST)
|
|
{
|
|
item.iImage = 10;
|
|
}
|
|
else if (pel->nType == ITEMTYPE_SITE)
|
|
{
|
|
item.iImage = 6;
|
|
}
|
|
else if (pel->nType == ITEMTYPE_DOMAIN)
|
|
{
|
|
item.iImage = 7;
|
|
}
|
|
else if (pel->nType == ITEMTYPE_OU)
|
|
{
|
|
item.iImage = 0;
|
|
}
|
|
else
|
|
{
|
|
if (pel->bDisabled)
|
|
{
|
|
item.iImage = 3;
|
|
}
|
|
else
|
|
{
|
|
item.iImage = 2;
|
|
}
|
|
}
|
|
|
|
item.lParam = (LPARAM)pel;
|
|
index = ListView_InsertItem(m_hList, &item);
|
|
if (index != -1 && pel->nType == ITEMTYPE_GPO)
|
|
{
|
|
// check to see if we need to add the domain name
|
|
LPOLESTR szObject = GetCurrentObject();
|
|
LPOLESTR szDomain = GetDomainFromLDAPPath(pel->szData);
|
|
if (szDomain && szObject)
|
|
{
|
|
// ignore potential differences in server name when we compare
|
|
// the domain paths
|
|
LPOLESTR szBuffer1 = NULL;
|
|
LPOLESTR szBuffer2 = NULL;
|
|
szBuffer1 = new OLECHAR[wcslen(szObject) + 1];
|
|
szBuffer2 = new OLECHAR[wcslen(szDomain) + 1];
|
|
if (NULL != szBuffer1 && NULL != szBuffer1)
|
|
{
|
|
CopyAsFriendlyName(szBuffer1, szObject);
|
|
CopyAsFriendlyName(szBuffer2, szDomain);
|
|
if (0 != wcscmp(szBuffer1, szBuffer2))
|
|
{
|
|
// Need to add the domain name since the domain is different
|
|
// from the focus object.
|
|
|
|
// Need to convert the domain to a friendly name.
|
|
// Let's just do it in place so I don't have to allocate any
|
|
// more memory. :)
|
|
// We can get away with this because the string can only get smaller.
|
|
CopyAsFriendlyName(szDomain, szDomain);
|
|
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_TEXT;
|
|
item.iItem = index;
|
|
item.iSubItem = 1;
|
|
item.pszText = szDomain;
|
|
ListView_SetItem(m_hList, &item);
|
|
}
|
|
}
|
|
if (szBuffer1)
|
|
{
|
|
delete [] szBuffer1;
|
|
}
|
|
if (szBuffer2)
|
|
{
|
|
delete [] szBuffer2;
|
|
}
|
|
}
|
|
|
|
if (szDomain)
|
|
delete [] szDomain;
|
|
if (szObject)
|
|
delete [] szObject;
|
|
}
|
|
return (index);
|
|
}
|
|
|
|
#include "ntdsapi.h"
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::FillSitesList
|
|
//
|
|
// Synopsis: Fills the combobox with the trusted sites information.
|
|
// The szData member of the combobox element structure is the
|
|
// containing domain.
|
|
//
|
|
// Returns: TRUE - successful
|
|
// FALSE - error
|
|
//
|
|
// History: 05-04-1998 stevebl created
|
|
// 05-27-1999 stevebl now initializes to site in lpInitialOU
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::FillSitesList ()
|
|
{
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
PDS_NAME_RESULTW pSites;
|
|
int iInitialSite = 0;
|
|
int iIndex = -1;
|
|
HANDLE hDs;
|
|
|
|
DWORD dw = DsBindW(NULL, NULL, &hDs);
|
|
if (ERROR_SUCCESS == dw)
|
|
{
|
|
dw = DsListSitesW(hDs, &pSites);
|
|
if (ERROR_SUCCESS == dw)
|
|
{
|
|
DWORD n = 0;
|
|
for (n = 0; n < pSites->cItems; n++)
|
|
{
|
|
//
|
|
// Add the site name (if it has a name)
|
|
//
|
|
if (pSites->rItems[n].pName)
|
|
{
|
|
LPTSTR lpFullPath, lpTempPath;
|
|
LOOKDATA * pdata;
|
|
pdata = new LOOKDATA;
|
|
if (pdata)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ulNoChars;
|
|
|
|
ulNoChars = wcslen(pSites->rItems[n].pName)+1;
|
|
pdata->szName = new WCHAR[ulNoChars];
|
|
if (pdata->szName)
|
|
{
|
|
hr = StringCchCopy(pdata->szName, ulNoChars, pSites->rItems[n].pName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
|
|
pdata->szData = NULL;
|
|
|
|
ulNoChars = lstrlen(pSites->rItems[n].pName) + 10;
|
|
lpTempPath = (LPTSTR) LocalAlloc (LPTR, ulNoChars * sizeof(TCHAR));
|
|
|
|
if (lpTempPath)
|
|
{
|
|
hr = StringCchCopy (lpTempPath, ulNoChars, TEXT("LDAP://"));
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
hr = StringCchCat (lpTempPath, ulNoChars, pSites->rItems[n].pName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
lpFullPath = GetFullPath (lpTempPath, m_hwndDlg);
|
|
|
|
if (lpFullPath)
|
|
{
|
|
ulNoChars = wcslen(lpFullPath)+1;
|
|
pdata->szData = new WCHAR[ulNoChars];
|
|
if (pdata->szData)
|
|
{
|
|
hr = StringCchCopy(pdata->szData, ulNoChars, lpFullPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
|
|
LocalFree (lpFullPath);
|
|
}
|
|
|
|
LocalFree (lpTempPath);
|
|
}
|
|
|
|
if (!pdata->szData)
|
|
{
|
|
if (pdata->szName)
|
|
{
|
|
delete [] pdata->szName;
|
|
}
|
|
|
|
delete pdata;
|
|
continue;
|
|
}
|
|
|
|
// try and use a friendlier name for the site
|
|
{
|
|
IADs * pADs = NULL;
|
|
// Get the friendly display name
|
|
hr = OpenDSObject(pdata->szData, IID_IADs,
|
|
(void **)&pADs);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT varName;
|
|
BSTR bstrNameProp;
|
|
VariantInit(&varName);
|
|
bstrNameProp = SysAllocString(SITE_NAME_PROPERTY);
|
|
|
|
if (bstrNameProp)
|
|
{
|
|
hr = pADs->Get(bstrNameProp, &varName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulNoChars = wcslen(varName.bstrVal) + 1;
|
|
LPOLESTR sz = new OLECHAR[ulNoChars];
|
|
if (sz)
|
|
{
|
|
hr = StringCchCopy(sz, ulNoChars, varName.bstrVal);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
if (pdata->szName)
|
|
delete [] pdata->szName;
|
|
pdata->szName = sz;
|
|
}
|
|
}
|
|
SysFreeString(bstrNameProp);
|
|
}
|
|
VariantClear(&varName);
|
|
pADs->Release();
|
|
}
|
|
}
|
|
pdata->nIndent = 0;
|
|
pdata->nType = ITEMTYPE_SITE;
|
|
|
|
iIndex = (int)SendMessage(m_hCombo, CB_INSERTSTRING, (WPARAM) -1, (LPARAM) (LPCTSTR) pdata);
|
|
if (CB_ERR == iIndex)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddSitesList: Failed to alloc memory with %d"), GetLastError()));
|
|
}
|
|
if (NULL != pdata->szData && NULL != m_pGBI->lpInitialOU)
|
|
{
|
|
if (0 == wcscmp(pdata->szData, m_pGBI->lpInitialOU))
|
|
{
|
|
iInitialSite = iIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DsFreeNameResultW(pSites);
|
|
}
|
|
DsUnBindW(&hDs);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddSitesList: DsBindW failed with 0x%x"), dw));
|
|
ReportError(m_hwndDlg, dw, IDS_DSBINDFAILED);
|
|
}
|
|
|
|
if (iIndex >= 0)
|
|
{
|
|
SendMessage (m_hCombo, CB_SETCURSEL, iInitialSite, 0);
|
|
}
|
|
SetCursor(hcur);
|
|
return TRUE;
|
|
}
|
|
|
|
PDS_DOMAIN_TRUSTS Domains;
|
|
|
|
int __cdecl CompareDomainInfo(const void * arg1, const void * arg2)
|
|
{
|
|
WCHAR * sz1, *sz2;
|
|
sz1 = Domains[*(ULONG *)arg1].DnsDomainName;
|
|
sz2 = Domains[*(ULONG *)arg2].DnsDomainName;
|
|
if (!sz1)
|
|
{
|
|
sz1 = Domains[*(ULONG *)arg1].NetbiosDomainName;
|
|
}
|
|
if (!sz2)
|
|
{
|
|
sz2 = Domains[*(ULONG *)arg2].NetbiosDomainName;
|
|
}
|
|
return _wcsicmp(sz1,sz2);
|
|
}
|
|
|
|
typedef struct tag_WORKING_LIST_EL
|
|
{
|
|
ULONG index;
|
|
struct tag_WORKING_LIST_EL * pNext;
|
|
} WORKING_LIST_EL;
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: BuildDomainList
|
|
//
|
|
// Synopsis: Builds a tree containing all domains that have a trust
|
|
// relationship with the server.
|
|
//
|
|
// Siblings within the tree are alphabetized.
|
|
//
|
|
// Arguments: [szServerName] - (NULL for local)
|
|
//
|
|
// Returns: pointer to the root node of the tree (NULL on error)
|
|
//
|
|
// History: 10-16-1998 stevebl Created
|
|
//
|
|
// Notes: Tree nodes must be freed by the caller (using delete).
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
LOOKDATA * BuildDomainList(WCHAR * szServerName)
|
|
{
|
|
ULONG DomainCount;
|
|
OLECHAR szBuffer[128];
|
|
HRESULT hr;
|
|
ULONG ulNoChars;
|
|
|
|
#if FGPO_SUPPORT
|
|
LOOKDATA * pDomainList = new LOOKDATA;
|
|
|
|
if (!pDomainList)
|
|
{
|
|
// failed to even create the Forest node!
|
|
return NULL;
|
|
}
|
|
|
|
pDomainList->szData = GetPathToForest(szServerName);
|
|
|
|
if (!pDomainList->szData)
|
|
{
|
|
delete pDomainList;
|
|
return NULL;
|
|
}
|
|
|
|
// load the name for the forest from resources
|
|
if (0 == LoadStringW(g_hInstance, IDS_FOREST, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])))
|
|
{
|
|
// failed to get the resource name
|
|
delete pDomainList;
|
|
return NULL;
|
|
}
|
|
|
|
ulNoChars = lstrlen(szBuffer) + 1;
|
|
pDomainList->szName = new OLECHAR [ulNoChars];
|
|
if (NULL == pDomainList->szName)
|
|
{
|
|
// not enough memory to create name of the forest node
|
|
delete pDomainList;
|
|
return NULL;
|
|
}
|
|
hr = StringCchCopy(pDomainList->szName, ulNoChars, szBuffer);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
pDomainList->nIndent = 0;
|
|
pDomainList->nType = ITEMTYPE_FOREST;
|
|
pDomainList->pParent = NULL;
|
|
pDomainList->pSibling = NULL;
|
|
pDomainList->pChild = NULL;
|
|
#else
|
|
LOOKDATA * pDomainList = NULL;
|
|
#endif
|
|
|
|
long l = DsEnumerateDomainTrusts(szServerName,
|
|
DS_DOMAIN_IN_FOREST | DS_DOMAIN_NATIVE_MODE |
|
|
DS_DOMAIN_PRIMARY | DS_DOMAIN_TREE_ROOT,
|
|
&Domains,
|
|
&DomainCount);
|
|
//
|
|
// Some of the below code might be unnecessary since DsEnumerateTrusts will no
|
|
// longer return domains from other forests. Shouldn't do any harm though..
|
|
//
|
|
|
|
if ((0 == l) && (DomainCount > 0))
|
|
{
|
|
// sort the list of domains alphabetically
|
|
ULONG * rgSorted = new ULONG[DomainCount];
|
|
if (rgSorted)
|
|
{
|
|
ULONG uCount = DomainCount;
|
|
while (uCount--)
|
|
{
|
|
rgSorted[uCount] = uCount;
|
|
}
|
|
qsort(rgSorted, DomainCount, sizeof (ULONG), CompareDomainInfo);
|
|
|
|
// Build a working list of the domains, sorted alphabetically in
|
|
// INVERTED order.
|
|
|
|
WORKING_LIST_EL * pWorkList = NULL;
|
|
|
|
LOOKDATA ** rgDataMap = new LOOKDATA * [DomainCount];
|
|
if (rgDataMap)
|
|
{
|
|
uCount = 0;
|
|
while (uCount < DomainCount)
|
|
{
|
|
WORKING_LIST_EL * pNew = new WORKING_LIST_EL;
|
|
if (pNew)
|
|
{
|
|
pNew->index = rgSorted[uCount];
|
|
pNew->pNext = pWorkList;
|
|
pWorkList = pNew;
|
|
}
|
|
rgDataMap[uCount] = NULL;
|
|
uCount++;
|
|
}
|
|
|
|
// Build the ordered tree of domains by removing domains from the
|
|
// working list and inserting them into the new tree until there are
|
|
// none left in the working list.
|
|
|
|
// NOTE - if this routine runs out of memory it will begin
|
|
// to drop nodes rather than AV.
|
|
|
|
WORKING_LIST_EL ** ppWorker;
|
|
|
|
BOOL fContinue = TRUE;
|
|
while (pWorkList && fContinue)
|
|
{
|
|
fContinue = FALSE;
|
|
ppWorker = &pWorkList;
|
|
while (*ppWorker)
|
|
{
|
|
if (NULL == Domains[(*ppWorker)->index].DnsDomainName)
|
|
{
|
|
//
|
|
// For now, if it doesn't have a
|
|
// DnsDomainName then we're going to
|
|
// skip it.
|
|
// Eventually we'll want to make sure it doesn't
|
|
// have a DC by calling DsGetDcName with
|
|
// DS_DIRECTORY_SERVICE_PREFERRED.
|
|
|
|
// remove it from the worker list
|
|
WORKING_LIST_EL * pNext = (*ppWorker)->pNext;
|
|
delete *ppWorker;
|
|
*ppWorker = pNext;
|
|
}
|
|
else
|
|
{
|
|
// Does this node have a parent?
|
|
ULONG flags = Domains[(*ppWorker)->index].Flags;
|
|
if ((0 != (flags & DS_DOMAIN_IN_FOREST)) && (0 == (flags & DS_DOMAIN_TREE_ROOT)))
|
|
{
|
|
// it has a parent has its parent been added?
|
|
LOOKDATA * pParent = rgDataMap[Domains[(*ppWorker)->index].ParentIndex];
|
|
if (pParent != NULL)
|
|
{
|
|
// its parent has been added
|
|
// insert this one in its parent's child list
|
|
LOOKDATA * pData = new LOOKDATA;
|
|
if (pData)
|
|
{
|
|
|
|
WCHAR * szName = Domains[(*ppWorker)->index].DnsDomainName;
|
|
if (!szName)
|
|
{
|
|
szName = Domains[(*ppWorker)->index].NetbiosDomainName;
|
|
}
|
|
ulNoChars = wcslen(szName) + 1;
|
|
pData->szName = new WCHAR[ulNoChars];
|
|
if (pData->szName)
|
|
{
|
|
int cch = 0;
|
|
int count=0;
|
|
// count the dots in szName;
|
|
while (szName[count])
|
|
{
|
|
if (L'.' == szName[count])
|
|
{
|
|
cch++;
|
|
}
|
|
count++;
|
|
}
|
|
cch *= 3; // multiply the number of dots by 3;
|
|
cch += 11; // add 10 + 1 (for the null)
|
|
cch += count; // add the string size;
|
|
pData->szData = new WCHAR[cch];
|
|
if (pData->szData)
|
|
{
|
|
NameToPath(pData->szData, szName, cch);
|
|
hr = StringCchCopy(pData->szName, ulNoChars, szName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
pData->nIndent = pParent->nIndent+1;
|
|
pData->nType = ITEMTYPE_DOMAIN;
|
|
pData->pParent = pParent;
|
|
pData->pSibling = pParent->pChild;
|
|
pData->pChild = NULL;
|
|
pParent->pChild = pData;
|
|
rgDataMap[(*ppWorker)->index] = pData;
|
|
// make sure we remember
|
|
// that we added something
|
|
// to the master list (helps
|
|
// us avoid infinite loops
|
|
// in case of an error)
|
|
fContinue = TRUE;
|
|
}
|
|
else
|
|
{
|
|
delete [] pData->szName;
|
|
delete pData;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pData;
|
|
}
|
|
}
|
|
// and remove it from the worker list
|
|
WORKING_LIST_EL * pNext = (*ppWorker)->pNext;
|
|
delete *ppWorker;
|
|
*ppWorker = pNext;
|
|
}
|
|
else
|
|
{
|
|
// skip it for now
|
|
ppWorker = &((*ppWorker)->pNext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// it doesn't have a parent add it just under the forest
|
|
// level of the list
|
|
LOOKDATA * pData = new LOOKDATA;
|
|
if (pData)
|
|
{
|
|
WCHAR * szName = Domains[(*ppWorker)->index].DnsDomainName;
|
|
if (!szName)
|
|
{
|
|
szName = Domains[(*ppWorker)->index].NetbiosDomainName;
|
|
}
|
|
ulNoChars = wcslen(szName) + 1;
|
|
pData->szName = new WCHAR[ulNoChars];
|
|
if (pData->szName)
|
|
{
|
|
int cch = 0;
|
|
int count=0;
|
|
// count the dots in szName;
|
|
while (szName[count])
|
|
{
|
|
if (L'.' == szName[count])
|
|
{
|
|
cch++;
|
|
}
|
|
count++;
|
|
}
|
|
cch *= 3; // multiply the number of dots by 3;
|
|
cch += 11; // add 10 + 1 for the null
|
|
cch += count; // add the string size;
|
|
pData->szData = new WCHAR[cch];
|
|
if (pData->szData)
|
|
{
|
|
NameToPath(pData->szData, szName, cch);
|
|
hr = StringCchCopy(pData->szName, ulNoChars, szName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
#if FGPO_SUPPORT
|
|
pData->nIndent = 1;
|
|
pData->nType = ITEMTYPE_DOMAIN;
|
|
pData->pParent = pDomainList;
|
|
pData->pSibling = pDomainList->pChild;
|
|
pData->pChild = NULL;
|
|
pDomainList->pChild = pData;
|
|
#else
|
|
pData->nIndent = 0;
|
|
pData->nType = ITEMTYPE_DOMAIN;
|
|
pData->pParent = NULL;
|
|
pData->pSibling = pDomainList;
|
|
pData->pChild = NULL;
|
|
pDomainList = pData;
|
|
#endif
|
|
rgDataMap[(*ppWorker)->index] = pData;
|
|
// make sure we remember
|
|
// that we added something
|
|
// to the master list (helps
|
|
// us avoid infinite loops
|
|
// in case of an error)
|
|
fContinue = TRUE;
|
|
}
|
|
else
|
|
{
|
|
delete [] pData->szName;
|
|
delete pData;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pData;
|
|
}
|
|
}
|
|
// and remove it from the worker list
|
|
WORKING_LIST_EL * pNext = (*ppWorker)->pNext;
|
|
delete *ppWorker;
|
|
*ppWorker = pNext;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
delete [] rgDataMap;
|
|
}
|
|
delete [] rgSorted;
|
|
}
|
|
NetApiBufferFree(Domains);
|
|
}
|
|
else
|
|
{
|
|
if (0 != l)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("DsEnumerateDomainTrustsW failed with %u"), l));
|
|
}
|
|
}
|
|
return pDomainList;
|
|
}
|
|
|
|
VOID FreeDomainInfo (LOOKDATA * pEntry)
|
|
{
|
|
|
|
if (!pEntry)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pEntry->pChild)
|
|
{
|
|
FreeDomainInfo (pEntry->pChild);
|
|
}
|
|
|
|
if (pEntry->pSibling)
|
|
{
|
|
FreeDomainInfo (pEntry->pSibling);
|
|
}
|
|
|
|
delete [] pEntry->szName;
|
|
delete pEntry;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::FillDomainList
|
|
//
|
|
// Synopsis: Fills the combobox with the trusted domain information.
|
|
// The szData member of the combobox element structure is the
|
|
// LDAP domain name.
|
|
//
|
|
// Returns: TRUE - successful
|
|
// FALSE - error
|
|
//
|
|
// History: 04-30-1998 stevebl Modified from original version
|
|
// written by EricFlo
|
|
// 10-20-1998 stevebl Heavily modified to support domains
|
|
// "outside the forest" and to fix a
|
|
// whole passle o' bugs.
|
|
//
|
|
// Note: This routine also sets the focus to the domain of the object
|
|
// passed in via the lpInitialOU member of the GPOBROWSEINFO
|
|
// structure.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::FillDomainList ()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
HRESULT hr;
|
|
DWORD dwIndex;
|
|
BOOL fEnableBackbutton = FALSE;
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
WCHAR * szBuffer1 = NULL;
|
|
if (m_pGBI->lpInitialOU)
|
|
{
|
|
if (IsForest(m_pGBI->lpInitialOU))
|
|
{
|
|
szBuffer1 = new TCHAR[128];
|
|
LoadStringW(g_hInstance, IDS_FOREST, szBuffer1, 128);
|
|
}
|
|
else
|
|
{
|
|
WCHAR * sz = GetDomainFromLDAPPath(m_pGBI->lpInitialOU);
|
|
if (sz)
|
|
{
|
|
szBuffer1 = new WCHAR[wcslen(sz) + 1];
|
|
if (szBuffer1)
|
|
{
|
|
CopyAsFriendlyName(szBuffer1, sz);
|
|
}
|
|
delete [] sz;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOOKDATA * pDomainList = BuildDomainList(m_szServerName);
|
|
|
|
if (!pDomainList)
|
|
{
|
|
ReportError(m_hwndDlg, GetLastError(), IDS_DOMAINLIST);
|
|
}
|
|
|
|
// Walk the ordered tree of domains, inserting each one into the
|
|
// dialog box
|
|
|
|
DWORD dwInitialDomain = -1;
|
|
|
|
// start at the head
|
|
while (pDomainList)
|
|
{
|
|
WCHAR * szBuffer2 = NULL;
|
|
// add this node
|
|
dwIndex = (DWORD)SendMessage(m_hCombo, CB_INSERTSTRING, (WPARAM) -1, (LPARAM)(LPCTSTR) pDomainList);
|
|
szBuffer2 = new WCHAR[wcslen(pDomainList->szData) + 1];
|
|
if (szBuffer2)
|
|
{
|
|
CopyAsFriendlyName(szBuffer2, pDomainList->szData);
|
|
}
|
|
if (NULL != szBuffer1 && NULL !=szBuffer2 && 0 ==_wcsicmp(szBuffer1, szBuffer2))
|
|
{
|
|
// replace the domain path with the path provided by the caller
|
|
// (because it contains the server)
|
|
|
|
WCHAR * sz = GetDomainFromLDAPPath(m_pGBI->lpInitialOU);
|
|
if (sz)
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("CBrowserPP::FillDomainList: Resetting domain path to user specified path: %s"), sz));
|
|
delete [] pDomainList->szData;
|
|
pDomainList->szData = sz;
|
|
}
|
|
dwInitialDomain = dwIndex;
|
|
if (pDomainList->nIndent > 0)
|
|
fEnableBackbutton = TRUE;
|
|
}
|
|
if (szBuffer2)
|
|
{
|
|
delete [] szBuffer2;
|
|
}
|
|
|
|
if (pDomainList->pChild)
|
|
{
|
|
// go to its child
|
|
pDomainList = pDomainList->pChild;
|
|
}
|
|
else
|
|
{
|
|
if (pDomainList->pSibling)
|
|
{
|
|
// go to its sibling if there are no children
|
|
pDomainList = pDomainList->pSibling;
|
|
}
|
|
else
|
|
{
|
|
// there are no children and no siblings
|
|
// back up until we find a parent with a sibling
|
|
// or there are no more parents (we're done)
|
|
do
|
|
{
|
|
pDomainList = pDomainList->pParent;
|
|
if (pDomainList)
|
|
{
|
|
if (pDomainList->pSibling)
|
|
{
|
|
pDomainList = pDomainList->pSibling;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
} while (TRUE);
|
|
}
|
|
}
|
|
}
|
|
if (szBuffer1)
|
|
{
|
|
delete [] szBuffer1;
|
|
}
|
|
|
|
if (-1 == dwInitialDomain)
|
|
{
|
|
// didn't find the initial domain anywhere in that list
|
|
// Set the first entry by default
|
|
dwInitialDomain = 0;
|
|
}
|
|
|
|
SendMessage (m_hCombo, CB_SETCURSEL, dwInitialDomain, 0);
|
|
SendMessage (m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_BACKBUTTON, (LPARAM) MAKELONG(fEnableBackbutton, 0));
|
|
SetCursor(hcur);
|
|
return bResult;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::SetInitialOU
|
|
//
|
|
// Synopsis: Adds nodes to the combobox until the initial OU specified by
|
|
// the caller via the lpInitalOU member of the GPOBROWSEINFO
|
|
// structure is present and gives it the focus.
|
|
//
|
|
// Returns: TRUE - success
|
|
//
|
|
// History: 10-20-1998 stevebl Created
|
|
//
|
|
// Notes: This routine assumes that FillDomainList() was just called.
|
|
// It will not work properly otherwise.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::SetInitialOU()
|
|
{
|
|
if (!m_pGBI->lpInitialOU)
|
|
{
|
|
// nothing requested so nothing required
|
|
return TRUE;
|
|
}
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::SetInitialOU: No object selected.")));
|
|
return FALSE;
|
|
}
|
|
|
|
// get the current object to see what's selected
|
|
LOOKDATA * pdataSelected = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdataSelected)
|
|
{
|
|
// is it the same as the requested object?
|
|
WCHAR * szSelected = NULL;
|
|
WCHAR * szRequested = NULL;
|
|
szSelected = new WCHAR[wcslen(pdataSelected->szData) + 1];
|
|
if (szSelected)
|
|
{
|
|
CopyAsFriendlyName(szSelected, pdataSelected->szData);
|
|
}
|
|
szRequested = new WCHAR[wcslen(m_pGBI->lpInitialOU + 1)];
|
|
if (NULL != szSelected && NULL != szRequested && 0 != wcscmp(szSelected, szRequested))
|
|
{
|
|
// it's not the same
|
|
// try and bind to the requested object
|
|
IADs * pADs = NULL;
|
|
HRESULT hr = OpenDSObject(m_pGBI->lpInitialOU,
|
|
IID_IADs, (void **)&pADs);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// the requested object exists and we have access permission
|
|
|
|
// now make sure that it's a domain or OU
|
|
BOOL fDomainOrOU = FALSE;
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
BSTR bstrProperty = SysAllocString(L"objectClass");
|
|
|
|
if (bstrProperty)
|
|
{
|
|
hr = pADs->Get(bstrProperty, &var);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int cElements = var.parray->rgsabound[0].cElements;
|
|
VARIANT * rgData = (VARIANT *)var.parray->pvData;
|
|
while (cElements--)
|
|
{
|
|
if (0 == _wcsicmp(L"domain", rgData[cElements].bstrVal))
|
|
{
|
|
fDomainOrOU = TRUE;
|
|
}
|
|
if (0 == _wcsicmp(L"organizationalUnit", rgData[cElements].bstrVal))
|
|
{
|
|
fDomainOrOU = TRUE;
|
|
}
|
|
}
|
|
}
|
|
SysFreeString(bstrProperty);
|
|
}
|
|
VariantClear(&var);
|
|
pADs->Release();
|
|
|
|
if (fDomainOrOU)
|
|
{
|
|
LOOKDATA * pLast = NULL;
|
|
LOOKDATA * pNew = NULL;
|
|
|
|
// build a list of nodes
|
|
// repeat removing leaf nodes until we're down to the domain
|
|
// (which will be the same as the selected object)
|
|
IADsPathname * pADsPathname = NULL;
|
|
BSTR bstr;
|
|
hr = CoCreateInstance(CLSID_Pathname,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname,
|
|
(LPVOID*)&pADsPathname);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrInitialOU = SysAllocString( m_pGBI->lpInitialOU );
|
|
if ( bstrInitialOU != NULL )
|
|
{
|
|
hr = pADsPathname->Set( bstrInitialOU, ADS_SETTYPE_FULL );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
while (TRUE)
|
|
{
|
|
// add this node to the list
|
|
hr = pADsPathname->Retrieve(ADS_FORMAT_X500, &bstr);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (szRequested)
|
|
{
|
|
delete [] szRequested;
|
|
}
|
|
szRequested = new WCHAR[wcslen(bstr) + 1];
|
|
if (szRequested)
|
|
{
|
|
CopyAsFriendlyName(szRequested, bstr);
|
|
}
|
|
if (NULL != szRequested && 0 == wcscmp(szSelected, szRequested))
|
|
{
|
|
// we're back to the first node
|
|
SysFreeString(bstr);
|
|
break;
|
|
}
|
|
|
|
pNew = new LOOKDATA;
|
|
if (!pNew)
|
|
{
|
|
// ran out of memory
|
|
SysFreeString(bstr);
|
|
break;
|
|
}
|
|
|
|
ULONG ulNoCharsRequested = wcslen(szRequested) + 1;
|
|
|
|
pNew->szName = new WCHAR[ulNoCharsRequested];
|
|
if (!pNew->szName)
|
|
{
|
|
// ran out of memory
|
|
delete pNew;
|
|
SysFreeString(bstr);
|
|
break;
|
|
}
|
|
|
|
ULONG ulNoChars = wcslen(bstr) + 1;
|
|
|
|
pNew->szData = new WCHAR[ulNoChars];
|
|
if (!pNew->szData)
|
|
{
|
|
// ran out of memory
|
|
delete [] pNew->szName;
|
|
delete pNew;
|
|
SysFreeString(bstr);
|
|
break;
|
|
}
|
|
hr = StringCchCopy(pNew->szData, ulNoChars, bstr);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
hr = StringCchCopy(pNew->szName, ulNoCharsRequested, szRequested);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
SysFreeString(bstr);
|
|
pNew->nIndent = 0;
|
|
pNew->nType = ITEMTYPE_OU;
|
|
pNew->pParent = NULL;
|
|
pNew->pSibling = NULL;
|
|
pNew->pChild = pLast;
|
|
if (pLast)
|
|
{
|
|
pLast->pParent = pNew;
|
|
}
|
|
pLast = pNew;
|
|
|
|
// strip off a leaf node and go again
|
|
|
|
hr = pADsPathname->RemoveLeafElement();
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SysFreeString( bstrInitialOU );
|
|
}
|
|
pADsPathname->Release();
|
|
}
|
|
|
|
// At this point I should have a list of LOOKDATA nodes
|
|
// (in pLast).
|
|
// The only things left to do are to link them into the
|
|
// tree, set their nIndent members, add them to the combo
|
|
// box and set the combo box's focus to the last one.
|
|
|
|
if (pLast)
|
|
{
|
|
// link in the list
|
|
pLast->pSibling = pdataSelected->pChild;
|
|
pLast->pParent = pdataSelected;
|
|
pLast->nIndent = pdataSelected->nIndent+1;
|
|
pdataSelected->pChild = pLast;
|
|
// now walk the tree, adding entries to the combo box
|
|
// and updating the nIndent members
|
|
while (pLast)
|
|
{
|
|
iIndex = (int)SendMessage(m_hCombo, CB_INSERTSTRING, iIndex+1, (LPARAM)(LPCTSTR) pLast);
|
|
|
|
if (pLast->pChild)
|
|
{
|
|
pLast->pChild->nIndent = pLast->nIndent+1;
|
|
}
|
|
pLast = pLast->pChild;
|
|
}
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
SendMessage(m_hCombo, CB_SETCURSEL, iIndex, 0);
|
|
SendMessage(m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_BACKBUTTON, (LPARAM) MAKELONG(TRUE, 0));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (szSelected)
|
|
{
|
|
delete [] szSelected;
|
|
}
|
|
if (szRequested)
|
|
{
|
|
delete [] szRequested;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::GetCurrentObject
|
|
//
|
|
// Synopsis: returns the LDAP path to the currently selected object
|
|
//
|
|
// Arguments: [] -
|
|
//
|
|
// Returns: NULL if no ojbect is selected else the LDAP path of the object
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// History: 5-05-1998 stevebl Created
|
|
// 06-23-1999 stevebl Added logic to give DCs names
|
|
//
|
|
// Notes:
|
|
// Checks to see if a domain has a named server. If it doesn't
|
|
// then it calls GetDCName to get it one.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
LPOLESTR CBrowserPP::GetCurrentObject()
|
|
{
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetCurrentObject: No object selected.")));
|
|
return NULL;
|
|
}
|
|
|
|
LPOLESTR sz=NULL;
|
|
LOOKDATA * pdata = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdata)
|
|
{
|
|
if (pdata->szData)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ulNoChars;
|
|
|
|
if (ITEMTYPE_DOMAIN == pdata->nType)
|
|
{
|
|
// make sure that domains are resolved to a server
|
|
LPTSTR szServer = ExtractServerName(pdata->szData);
|
|
if (NULL == szServer)
|
|
{
|
|
LPWSTR szTemp = GetDCName(pdata->szName, NULL, NULL, TRUE, 0);
|
|
if (szTemp)
|
|
{
|
|
LPWSTR szFullPath = MakeFullPath(pdata->szData, szTemp);
|
|
if (szFullPath)
|
|
{
|
|
ulNoChars = wcslen(szFullPath)+1;
|
|
LPWSTR szTemp2 = new WCHAR[ulNoChars];
|
|
if (szTemp2)
|
|
{
|
|
hr = StringCchCopy (szTemp2, ulNoChars, szFullPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
delete [] pdata->szData;
|
|
pdata->szData = szTemp2;
|
|
}
|
|
LocalFree(szFullPath);
|
|
}
|
|
LocalFree(szTemp);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LocalFree(szServer);
|
|
}
|
|
}
|
|
|
|
ulNoChars = wcslen(pdata->szData) + 1;
|
|
sz = new OLECHAR[ulNoChars];
|
|
if (sz)
|
|
{
|
|
hr = StringCchCopy(sz, ulNoChars, pdata->szData);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::IsCurrentObjectAForest
|
|
//
|
|
// Synopsis: tests to see if the currently selected object is a forest
|
|
//
|
|
// Arguments: [] -
|
|
//
|
|
// Returns: TRUE - if it is a forest
|
|
// FALSE - otherwise
|
|
//
|
|
// History: 03-31-2000 stevebl Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::IsCurrentObjectAForest()
|
|
{
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::IsCurrentObjectAForest: No object selected.")));
|
|
return FALSE;
|
|
}
|
|
|
|
LOOKDATA * pdata = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
return (ITEMTYPE_FOREST == pdata->nType);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::GetCurrentDomain
|
|
//
|
|
// Synopsis: returns the domain of the currently selecte object (if the
|
|
// currently currently selected object is the domain then they
|
|
// are one and the same)
|
|
//
|
|
// Arguments: [] -
|
|
//
|
|
// Returns: NULL - if no object is selected else returns LDAP path of
|
|
// domain
|
|
//
|
|
// History: 05-04-1998 stevebl Created
|
|
// 06-23-1999 stevebl Added logic to give DCs names
|
|
//
|
|
// Notes: Checks to see if a domain has a named server. If it doesn't
|
|
// then it calls GetDCName to get it one.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
LPOLESTR CBrowserPP::GetCurrentDomain()
|
|
{
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetCurrentDomain: No object selected.")));
|
|
return NULL;
|
|
}
|
|
|
|
LOOKDATA * pdata = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
switch (pdata->nType)
|
|
{
|
|
case ITEMTYPE_DOMAIN:
|
|
{
|
|
if (pdata->szData)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ulNoChars;
|
|
|
|
// make sure the domain has a server
|
|
LPTSTR szServer = ExtractServerName(pdata->szData);
|
|
if (NULL == szServer)
|
|
{
|
|
LPWSTR szTemp = GetDCName(pdata->szName, NULL, NULL, TRUE, 0);
|
|
if (szTemp)
|
|
{
|
|
LPWSTR szFullPath = MakeFullPath(pdata->szData, szTemp);
|
|
if (szFullPath)
|
|
{
|
|
ulNoChars = wcslen(szFullPath)+1;
|
|
LPWSTR sz = new WCHAR[ulNoChars];
|
|
if (sz)
|
|
{
|
|
hr = StringCchCopy(sz, ulNoChars, szFullPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
delete [] pdata->szData;
|
|
pdata->szData = sz;
|
|
}
|
|
LocalFree(szFullPath);
|
|
}
|
|
LocalFree(szTemp);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LocalFree(szServer);
|
|
}
|
|
ulNoChars = wcslen(pdata->szData)+1;
|
|
LPOLESTR sz = new OLECHAR[ulNoChars];
|
|
if (sz)
|
|
{
|
|
hr = StringCchCopy(sz, ulNoChars, pdata->szData);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
return sz;
|
|
}
|
|
return NULL;
|
|
}
|
|
case ITEMTYPE_FOREST:
|
|
case ITEMTYPE_SITE:
|
|
case ITEMTYPE_OU:
|
|
{
|
|
return GetDomainFromLDAPPath(pdata->szData);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL CBrowserPP::AddGPOsLinkedToObject()
|
|
{
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
LPOLESTR lpObject;
|
|
HRESULT hr;
|
|
IADs * pADs = NULL;
|
|
IADs * pADsGPO;
|
|
VARIANT var;
|
|
BSTR bstrProperty;
|
|
BOOL fResult = FALSE;
|
|
int index = ListView_GetItemCount(m_hList);
|
|
|
|
//
|
|
// Get the current object name
|
|
//
|
|
lpObject = GetCurrentObject();
|
|
if (NULL == lpObject)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("CBrowserPP::AddGPOsLinkedToObject: Reading gPLink property from %s"), lpObject));
|
|
|
|
hr = OpenDSObject(lpObject, IID_IADs, (void **)&pADs);
|
|
|
|
delete [] lpObject;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddGPOsLinkedToObject: OpenDSObject failed with 0x%x"), hr));
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDGPLINK);
|
|
goto Exit;
|
|
}
|
|
|
|
VariantInit(&var);
|
|
|
|
bstrProperty = SysAllocString(GPM_LINK_PROPERTY);
|
|
|
|
if (bstrProperty)
|
|
{
|
|
hr = pADs->Get(bstrProperty, &var);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPOLESTR szGPOList = var.bstrVal;
|
|
OLECHAR * pchTemp;
|
|
OLECHAR * pchGPO;
|
|
VARIANT varName;
|
|
BSTR bstrNameProp;
|
|
|
|
if (szGPOList)
|
|
{
|
|
OLECHAR * szGPO = new WCHAR[wcslen(szGPOList) + 1];
|
|
if (szGPO)
|
|
{
|
|
pchTemp = szGPOList;
|
|
while (TRUE)
|
|
{
|
|
// Look for the [
|
|
while (*pchTemp && (*pchTemp != L'['))
|
|
pchTemp++;
|
|
if (!(*pchTemp))
|
|
break;
|
|
|
|
pchTemp++;
|
|
|
|
// Copy the GPO name
|
|
pchGPO = szGPO;
|
|
|
|
while (*pchTemp && (*pchTemp != L';'))
|
|
*pchGPO++ = *pchTemp++;
|
|
|
|
*pchGPO = L'\0';
|
|
|
|
// Add the object to the list view
|
|
MYLISTEL * pel = new MYLISTEL;
|
|
if (pel)
|
|
{
|
|
|
|
pel->szData = NULL;
|
|
pel->bDisabled = FALSE;
|
|
|
|
LPTSTR szFullGPOPath = GetFullPath(szGPO, m_hwndDlg);
|
|
|
|
if (szFullGPOPath)
|
|
{
|
|
ULONG ulNoChars = wcslen(szFullGPOPath) + 1;
|
|
pel->szData = new WCHAR[ulNoChars];
|
|
if (pel->szData)
|
|
{
|
|
hr = StringCchCopy(pel->szData, ulNoChars, szFullGPOPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddGPOsLinkedToObject: Failed to allocate memory for new full gpo path")));
|
|
LocalFree(szFullGPOPath);
|
|
delete pel;
|
|
continue;
|
|
}
|
|
|
|
LocalFree(szFullGPOPath);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddGPOsLinkedToObject: Failed to get full gpo path")));
|
|
delete pel;
|
|
continue;
|
|
}
|
|
|
|
VariantInit(&varName);
|
|
|
|
// get the friendly display name
|
|
hr = OpenDSObject(pel->szData, IID_IADs,
|
|
(void **)&pADsGPO);
|
|
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
|
|
{
|
|
delete pel;
|
|
continue;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bstrNameProp = SysAllocString(GPO_NAME_PROPERTY);
|
|
|
|
if (bstrNameProp)
|
|
{
|
|
hr = pADsGPO->Get(bstrNameProp, &varName);
|
|
SysFreeString(bstrNameProp);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
pADsGPO->Release();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddGPOsLinkedToObject: Couldn't get display name for %s with 0x%x"), pel->szData, hr));
|
|
pel->szName = new WCHAR[200];
|
|
if (pel->szName)
|
|
{
|
|
LoadString(g_hInstance, IDS_GPM_NOGPONAME, pel->szName, 200);
|
|
}
|
|
pel->bDisabled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ULONG ulNoChars = wcslen(varName.bstrVal) + 1;
|
|
pel->szName = new WCHAR[ulNoChars];
|
|
if (pel->szName)
|
|
{
|
|
hr = StringCchCopy(pel->szName, ulNoChars, varName.bstrVal);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
|
|
VariantClear(&varName);
|
|
|
|
pel->nType = ITEMTYPE_GPO;
|
|
|
|
AddElement(pel, index);
|
|
}
|
|
}
|
|
delete [] szGPO;
|
|
}
|
|
}
|
|
}
|
|
|
|
SysFreeString(bstrProperty);
|
|
}
|
|
|
|
VariantClear(&var);
|
|
|
|
fResult = TRUE;
|
|
|
|
Exit:
|
|
if (pADs)
|
|
{
|
|
pADs->Release();
|
|
}
|
|
SetCursor(hcur);
|
|
return fResult;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::AddGPOsForDomain
|
|
//
|
|
// Synopsis: Adds all the GPOs in the specified domain to the list view
|
|
// control. The szData member of the list element structure
|
|
// contains the LDAP path of the GPO.
|
|
//
|
|
// The domain is indicated by the currently selected combobox
|
|
// element.
|
|
//
|
|
// Returns: TRUE - successful
|
|
// FALSE - error
|
|
//
|
|
// History: 04-30-1998 stevebl Modified from original routine
|
|
// written by EricFlo.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::AddGPOsForDomain()
|
|
{
|
|
LPTSTR lpDomain;
|
|
LPTSTR lpGPO;
|
|
INT iIndex;
|
|
VARIANT var;
|
|
VARIANT varGPO;
|
|
ULONG ulResult;
|
|
HRESULT hr = E_FAIL;
|
|
IADsPathname * pADsPathname = NULL;
|
|
IADs * pADs = NULL;
|
|
IADsContainer * pADsContainer = NULL;
|
|
IDispatch * pDispatch = NULL;
|
|
IEnumVARIANT *pVar = NULL;
|
|
BSTR bstrContainer = NULL;
|
|
BSTR bstrCommonName = NULL;
|
|
BSTR bstrDisplayName = NULL;
|
|
BSTR bstrGPO = NULL;
|
|
TCHAR szDisplayName[512];
|
|
TCHAR szCommonName[50];
|
|
MYLISTEL * pel;
|
|
ULONG ulNoChars;
|
|
|
|
//
|
|
// Test to see if we're focused on a forest
|
|
//
|
|
|
|
BOOL fForest = IsCurrentObjectAForest();
|
|
|
|
//
|
|
// Get the current domain name
|
|
//
|
|
|
|
lpDomain = GetCurrentDomain();
|
|
|
|
if (!lpDomain)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: NULL domain name.")));
|
|
return FALSE;
|
|
}
|
|
|
|
HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
//
|
|
// Create a pathname object we can work with
|
|
//
|
|
|
|
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname, (LPVOID*)&pADsPathname);
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to create adspathname instance with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the domain name
|
|
//
|
|
|
|
BSTR bstrDomain = SysAllocString( lpDomain );
|
|
if ( bstrDomain == NULL )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate BSTR memory.")));
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
hr = pADsPathname->Set (bstrDomain, ADS_SETTYPE_FULL);
|
|
SysFreeString( bstrDomain );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to set pathname with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
BSTR bstrFolder = NULL;
|
|
if (fForest)
|
|
{
|
|
//
|
|
// Add the configuration folder to the path
|
|
//
|
|
|
|
bstrFolder = SysAllocString( TEXT("CN=Configuration") );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add the system folder to the path
|
|
//
|
|
|
|
bstrFolder = SysAllocString( TEXT("CN=System") );
|
|
}
|
|
|
|
if ( bstrFolder == NULL )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate BSTR memory.")));
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
hr = pADsPathname->AddLeafElement (bstrFolder);
|
|
SysFreeString( bstrFolder );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to add system folder with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Add the policies container to the path
|
|
//
|
|
|
|
BSTR bstrCNPolicies = SysAllocString( TEXT("CN=Policies") );
|
|
if ( bstrCNPolicies == NULL )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate BSTR memory.")));
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
hr = pADsPathname->AddLeafElement (bstrCNPolicies);
|
|
SysFreeString( bstrCNPolicies );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to add policies folder with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Retreive the container path - this is the path to the policies folder
|
|
//
|
|
|
|
hr = pADsPathname->Retrieve (ADS_FORMAT_X500, &bstrContainer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to retreive container path with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Release the pathname object
|
|
//
|
|
|
|
pADsPathname->Release();
|
|
pADsPathname = NULL;
|
|
|
|
|
|
//
|
|
// Build an enumerator
|
|
//
|
|
|
|
hr = OpenDSObject(bstrContainer, IID_IADsContainer, (void **)&pADsContainer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr != HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("AddGPOsForDomain: Failed to get gpo container interface with 0x%x for object %s"),
|
|
hr, bstrContainer));
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDGPLINK);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
hr = ADsBuildEnumerator (pADsContainer, &pVar);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to get enumerator with 0x%x"), hr));
|
|
goto Exit;
|
|
}
|
|
|
|
bstrCommonName = SysAllocString (L"cn");
|
|
|
|
if (!bstrCommonName)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate memory with %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
bstrDisplayName = SysAllocString (GPO_NAME_PROPERTY);
|
|
|
|
if (!bstrDisplayName)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate memory with %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Enumerate
|
|
//
|
|
|
|
while (TRUE)
|
|
{
|
|
BOOL fNeedDisplayName = FALSE;
|
|
|
|
VariantInit(&var);
|
|
hr = ADsEnumerateNext(pVar, 1, &var, &ulResult);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("AddGPOsForDomain: Failed to enumerator with 0x%x"), hr));
|
|
VariantClear (&var);
|
|
break;
|
|
}
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
VariantClear (&var);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// If var.vt isn't VT_DISPATCH, we're finished.
|
|
//
|
|
|
|
if (var.vt != VT_DISPATCH)
|
|
{
|
|
VariantClear (&var);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// We found something, get the IDispatch interface
|
|
//
|
|
|
|
pDispatch = var.pdispVal;
|
|
|
|
if (!pDispatch)
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("AddGPOsForDomain: Failed to get IDispatch interface")));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Now query for the IADs interface so we can get some
|
|
// properties from this GPO.
|
|
//
|
|
|
|
hr = pDispatch->QueryInterface(IID_IADs, (LPVOID *)&pADs);
|
|
|
|
if (FAILED(hr)) {
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: QI for IADs failed with 0x%x"), hr));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the display name
|
|
//
|
|
|
|
VariantInit(&varGPO);
|
|
|
|
hr = pADs->Get(bstrDisplayName, &varGPO);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("AddGPOsForDomain: Failed to get display name with 0x%x"),hr));
|
|
fNeedDisplayName = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wcsncpy (szDisplayName, varGPO.bstrVal, (sizeof(szDisplayName) / sizeof(szDisplayName[0])) - 1);
|
|
}
|
|
|
|
VariantClear (&varGPO);
|
|
|
|
|
|
//
|
|
// Get the common name
|
|
//
|
|
|
|
VariantInit(&varGPO);
|
|
|
|
hr = pADs->Get(bstrCommonName, &varGPO);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("AddGPOsForDomain: Failed to get common name with 0x%x"),hr));
|
|
VariantClear (&varGPO);
|
|
pADs->Release();
|
|
goto LoopAgain;
|
|
}
|
|
|
|
hr = StringCchCopy (szCommonName, ARRAYSIZE(szCommonName), TEXT("CN="));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCat (szCommonName, ARRAYSIZE(szCommonName), varGPO.bstrVal);
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
VariantClear (&varGPO);
|
|
pADs->Release();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto LoopAgain;
|
|
}
|
|
|
|
//
|
|
// Create a pathname object so we can tack the common name
|
|
// onto the end of the LDAP path
|
|
//
|
|
|
|
hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname, (LPVOID*)&pADsPathname);
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to create adspathname instance with 0x%x"), hr));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the LDAP path
|
|
//
|
|
|
|
hr = pADsPathname->Set (bstrContainer, ADS_SETTYPE_FULL);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to set the ldap path with 0x%x"), hr));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the GPO's common name
|
|
//
|
|
|
|
BSTR bstrTmpCommonName = SysAllocString( szCommonName );
|
|
if ( bstrTmpCommonName == NULL )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to allocate BSTR memory.")));
|
|
hr = E_OUTOFMEMORY;
|
|
goto LoopAgain;
|
|
}
|
|
hr = pADsPathname->AddLeafElement (bstrTmpCommonName);
|
|
SysFreeString( bstrTmpCommonName );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to add the common name with 0x%x"), hr));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Retreive the gpo path
|
|
//
|
|
|
|
hr = pADsPathname->Retrieve (ADS_FORMAT_X500, &bstrGPO);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to retreive gpo path with 0x%x"), hr));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Make a copy of it
|
|
//
|
|
|
|
ulNoChars = wcslen(bstrGPO) + 1;
|
|
lpGPO = new WCHAR[ulNoChars];
|
|
|
|
if (!lpGPO)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("AddGPOsForDomain: Failed to alloc memory for gpo path with 0x%x"),
|
|
GetLastError()));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
hr = StringCchCopy (lpGPO, ulNoChars, bstrGPO);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
pel = new MYLISTEL;
|
|
if (pel)
|
|
{
|
|
if (fNeedDisplayName)
|
|
{
|
|
pel->szName = new WCHAR[wcslen(lpGPO) + 1];
|
|
if (pel->szName)
|
|
{
|
|
CopyAsFriendlyName(pel->szName, lpGPO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ulNoChars = wcslen(szDisplayName) + 1;
|
|
pel->szName = new WCHAR[ulNoChars];
|
|
if (pel->szName)
|
|
{
|
|
hr = StringCchCopy(pel->szName, ulNoChars, szDisplayName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
pel->szData = lpGPO;
|
|
pel->nType = ITEMTYPE_GPO;
|
|
pel->bDisabled = FALSE;
|
|
|
|
AddElement(pel, -1);
|
|
}
|
|
|
|
LoopAgain:
|
|
|
|
if (pADsPathname)
|
|
{
|
|
pADsPathname->Release();
|
|
pADsPathname = NULL;
|
|
}
|
|
|
|
if (bstrGPO)
|
|
{
|
|
SysFreeString (bstrGPO);
|
|
bstrGPO = NULL;
|
|
}
|
|
|
|
VariantClear (&var);
|
|
}
|
|
|
|
|
|
SendMessage (m_hList, LB_SETCURSEL, 0, 0);
|
|
|
|
Exit:
|
|
|
|
if (pVar)
|
|
{
|
|
ADsFreeEnumerator (pVar);
|
|
}
|
|
|
|
if (pADsPathname)
|
|
{
|
|
pADsPathname->Release();
|
|
}
|
|
|
|
if (pADsContainer)
|
|
{
|
|
pADsContainer->Release();
|
|
}
|
|
|
|
if (bstrContainer)
|
|
{
|
|
SysFreeString (bstrContainer);
|
|
}
|
|
|
|
if (bstrCommonName)
|
|
{
|
|
SysFreeString (bstrCommonName);
|
|
}
|
|
|
|
if (bstrDisplayName)
|
|
{
|
|
SysFreeString (bstrDisplayName);
|
|
}
|
|
|
|
if (lpDomain)
|
|
{
|
|
delete [] lpDomain;
|
|
}
|
|
|
|
SetCursor(hcur);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::AddChildContainers
|
|
//
|
|
// Synopsis: Adds the child domains and OUs for the currently selected object
|
|
//
|
|
// History: 05-006-1998 stevebl Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL CBrowserPP::AddChildContainers()
|
|
{
|
|
LPOLESTR szObject = NULL;
|
|
HRESULT hr;
|
|
ULONG ulNoChars;
|
|
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddChildContainers: No object selected.")));
|
|
return FALSE;
|
|
}
|
|
|
|
LOOKDATA * pdata = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdata)
|
|
{
|
|
if (ITEMTYPE_DOMAIN == pdata->nType)
|
|
{
|
|
// make sure that domains are resolved to a server
|
|
LPTSTR szServer = ExtractServerName(pdata->szData);
|
|
if (NULL == szServer)
|
|
{
|
|
BOOL bDCFound = FALSE;
|
|
LPWSTR szTemp = GetDCName(pdata->szName, NULL, NULL, TRUE, 0);
|
|
if (szTemp)
|
|
{
|
|
LPWSTR szFullPath = MakeFullPath(pdata->szData, szTemp);
|
|
if (szFullPath)
|
|
{
|
|
ulNoChars = wcslen(szFullPath)+1;
|
|
LPWSTR sz = new WCHAR[ulNoChars];
|
|
if (sz)
|
|
{
|
|
hr = StringCchCopy(sz, ulNoChars, szFullPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
delete [] pdata->szData;
|
|
pdata->szData = sz;
|
|
bDCFound = TRUE;
|
|
}
|
|
LocalFree(szFullPath);
|
|
}
|
|
LocalFree(szTemp);
|
|
}
|
|
|
|
if (!bDCFound)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::AddChildContainers: Failed to get a DC name for %s"),
|
|
pdata->szName));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LocalFree(szServer);
|
|
}
|
|
}
|
|
LOOKDATA * pChild = pdata->pChild;
|
|
while (pChild)
|
|
{
|
|
// Add child domains this way since ADsEnumerateNext doesn't
|
|
// seem to be giving them to us.
|
|
if (ITEMTYPE_DOMAIN == pChild->nType)
|
|
{
|
|
// got something we can work with
|
|
MYLISTEL * pel = new MYLISTEL;
|
|
if (pel)
|
|
{
|
|
memset(pel, 0, sizeof(MYLISTEL));
|
|
ulNoChars = wcslen(pChild->szData) + 1;
|
|
pel->szData = new OLECHAR[ulNoChars];
|
|
if (pel->szData)
|
|
{
|
|
hr = StringCchCopy(pel->szData, ulNoChars, pChild->szData);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
|
|
ulNoChars = wcslen(pChild->szName) + 1;
|
|
pel->szName = new OLECHAR[ulNoChars];
|
|
if (pel->szName)
|
|
{
|
|
hr = StringCchCopy(pel->szName, ulNoChars, pChild->szName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
pel->bDisabled = FALSE;
|
|
pel->nType = ITEMTYPE_DOMAIN;
|
|
INT index = -1;
|
|
AddElement(pel, -1);
|
|
}
|
|
pChild = pChild->pSibling;
|
|
}
|
|
|
|
}
|
|
szObject = pdata->szData;
|
|
m_pPrevSel = pdata;
|
|
} else {
|
|
m_pPrevSel = NULL;
|
|
}
|
|
|
|
if ( ! szObject )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
IADsContainer * pADsContainer;
|
|
|
|
hr = OpenDSObject(szObject, IID_IADsContainer, (void **)&pADsContainer);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IEnumVARIANT *pVar;
|
|
hr = ADsBuildEnumerator(pADsContainer, &pVar);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
ULONG ulResult;
|
|
|
|
while (SUCCEEDED(ADsEnumerateNext(pVar, 1, &var, &ulResult)))
|
|
{
|
|
if (0 == ulResult)
|
|
{
|
|
break;
|
|
}
|
|
if (var.vt == VT_DISPATCH)
|
|
{
|
|
// query for the IADs interface so we can get its properties
|
|
IADs * pDSObject;
|
|
hr = var.pdispVal->QueryInterface(IID_IADs, (LPVOID *)&pDSObject);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstr;
|
|
DWORD dwType = -1;
|
|
hr = pDSObject->get_Class(&bstr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (0 == wcscmp(bstr, CLASSNAME_OU))
|
|
{
|
|
dwType = ITEMTYPE_OU;
|
|
}
|
|
else if (0 == wcscmp(bstr, CLASSNAME_DOMAIN))
|
|
{
|
|
dwType = ITEMTYPE_DOMAIN;
|
|
}
|
|
SysFreeString(bstr);
|
|
}
|
|
if (ITEMTYPE_DOMAIN == dwType || ITEMTYPE_OU == dwType)
|
|
{
|
|
// got something we can work with
|
|
MYLISTEL * pel = new MYLISTEL;
|
|
if (pel)
|
|
{
|
|
memset(pel, 0, sizeof(MYLISTEL));
|
|
hr = pDSObject->get_ADsPath(&bstr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulNoChars = wcslen(bstr) + 1;
|
|
pel->szData = new OLECHAR[ulNoChars];
|
|
if (pel->szData)
|
|
{
|
|
hr = StringCchCopy(pel->szData, ulNoChars, bstr);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
pel->szName = new OLECHAR[wcslen(bstr) + 1];
|
|
if (pel->szName)
|
|
{
|
|
// Need to convert to a friendly name.
|
|
CopyAsFriendlyName(pel->szName, bstr);
|
|
}
|
|
SysFreeString(bstr);
|
|
}
|
|
pel->nType = dwType;
|
|
INT index = -1;
|
|
AddElement(pel, -1);
|
|
}
|
|
}
|
|
pDSObject->Release();
|
|
}
|
|
}
|
|
VariantClear(&var);
|
|
}
|
|
|
|
ADsFreeEnumerator(pVar);
|
|
}
|
|
|
|
pADsContainer->Release();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::RefreshDomains
|
|
//
|
|
// Synopsis: refreshes the listview for the "domains" page
|
|
//
|
|
// History: 04-30-1998 stevebl Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CBrowserPP::RefreshDomains()
|
|
{
|
|
LONG lStyle;
|
|
|
|
ListView_DeleteAllItems(m_hList);
|
|
|
|
lStyle = GetWindowLong (m_hList, GWL_STYLE);
|
|
lStyle &= ~LVS_SORTASCENDING;
|
|
SetWindowLong (m_hList, GWL_STYLE, lStyle);
|
|
|
|
if (AddChildContainers())
|
|
{
|
|
AddGPOsLinkedToObject();
|
|
EnableWindow (m_hList, TRUE);
|
|
if (!(m_pGBI->dwFlags & GPO_BROWSE_DISABLENEW)) {
|
|
SendMessage (m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_NEWFOLDER, (LPARAM) MAKELONG(1, 0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EnableWindow (m_hList, FALSE);
|
|
SendMessage (m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_NEWFOLDER, (LPARAM) MAKELONG(0, 0));
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::RefreshSites
|
|
//
|
|
// Synopsis: refreshes the listview for the "sites" page
|
|
//
|
|
// History: 04-30-1998 stevebl Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CBrowserPP::RefreshSites()
|
|
{
|
|
LONG lStyle;
|
|
|
|
ListView_DeleteAllItems(m_hList);
|
|
|
|
lStyle = GetWindowLong (m_hList, GWL_STYLE);
|
|
lStyle &= ~LVS_SORTASCENDING;
|
|
SetWindowLong (m_hList, GWL_STYLE, lStyle);
|
|
|
|
AddGPOsLinkedToObject();
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CBrowserPP::RefreshAll
|
|
//
|
|
// Synopsis: refreshes the listview for the "all" page
|
|
//
|
|
// History: 04-30-1998 stevebl Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CBrowserPP::RefreshAll()
|
|
{
|
|
LONG lStyle;
|
|
|
|
ListView_DeleteAllItems(m_hList);
|
|
|
|
lStyle = GetWindowLong (m_hList, GWL_STYLE);
|
|
lStyle |= LVS_SORTASCENDING;
|
|
SetWindowLong (m_hList, GWL_STYLE, lStyle);
|
|
|
|
if (AddGPOsForDomain())
|
|
{
|
|
EnableWindow (m_hList, TRUE);
|
|
SendMessage (m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_NEWFOLDER, (LPARAM) MAKELONG(1, 0));
|
|
}
|
|
else
|
|
{
|
|
EnableWindow (m_hList, FALSE);
|
|
SendMessage (m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_NEWFOLDER, (LPARAM) MAKELONG(0, 0));
|
|
}
|
|
|
|
}
|
|
|
|
void CBrowserPP::SetButtonState()
|
|
{
|
|
if (ListView_GetNextItem (m_hList, -1, LVNI_ALL | LVNI_SELECTED) != -1)
|
|
{
|
|
EnableWindow (GetDlgItem(GetParent(m_hwndDlg), IDOK), TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow (GetDlgItem(GetParent(m_hwndDlg), IDOK), FALSE);
|
|
}
|
|
}
|
|
|
|
BOOL CBrowserPP::OnInitDialog()
|
|
{
|
|
DWORD dwDescription;
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
dwDescription = IDS_DOMAINDESCRIPTION;
|
|
break;
|
|
case PAGETYPE_SITES:
|
|
dwDescription = IDS_SITEDESCRIPTION;
|
|
break;
|
|
case PAGETYPE_ALL:
|
|
default:
|
|
dwDescription = IDS_ALLDESCRIPTION;
|
|
break;
|
|
}
|
|
WCHAR szDescription[MAX_PATH]; // this is a resource - size doesn't need to be dynamic
|
|
LoadString(g_hInstance, dwDescription, szDescription, MAX_PATH);
|
|
SetDlgItemText(m_hwndDlg, IDC_DESCRIPTION, szDescription);
|
|
|
|
m_hList = GetDlgItem(m_hwndDlg, IDC_LIST1);
|
|
m_ilSmall = ImageList_LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_16x16), SMALLICONSIZE, 0, RGB(255,0,255));
|
|
m_ilLarge = ImageList_LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_32x32), LARGEICONSIZE, 0, RGB(255, 0 ,255));
|
|
m_hCombo = GetDlgItem(m_hwndDlg, IDC_COMBO1);
|
|
|
|
RECT rect;
|
|
GetClientRect(m_hList, &rect);
|
|
WCHAR szText[32];
|
|
int dxScrollBar = GetSystemMetrics(SM_CXVSCROLL);
|
|
if (PAGETYPE_ALL == m_dwPageType)
|
|
{
|
|
LV_COLUMN lvcol;
|
|
memset(&lvcol, 0, sizeof(lvcol));
|
|
lvcol.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
|
lvcol.fmt = LVCFMT_LEFT;
|
|
lvcol.cx = (rect.right - rect.left) - dxScrollBar;
|
|
LoadString(g_hInstance, IDS_NAMECOLUMN, szText, 32);
|
|
lvcol.pszText = szText;
|
|
ListView_InsertColumn(m_hList, 0, &lvcol);
|
|
}
|
|
else
|
|
{
|
|
LV_COLUMN lvcol;
|
|
memset(&lvcol, 0, sizeof(lvcol));
|
|
lvcol.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
|
lvcol.fmt = LVCFMT_LEFT;
|
|
int cx = ((rect.right - rect.left) - dxScrollBar)*2/3;
|
|
lvcol.cx = cx;
|
|
LoadString(g_hInstance, IDS_NAMECOLUMN, szText, 32);
|
|
lvcol.pszText = szText;
|
|
ListView_InsertColumn(m_hList, 0, &lvcol);
|
|
memset(&lvcol, 0, sizeof(lvcol));
|
|
lvcol.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
|
lvcol.fmt = LVCFMT_LEFT;
|
|
lvcol.cx = ((rect.right - rect.left) - dxScrollBar) - cx;
|
|
LoadString(g_hInstance, IDS_DOMAINCOLUMN, szText, 32);
|
|
lvcol.pszText = szText;
|
|
ListView_InsertColumn(m_hList, 1, &lvcol);
|
|
}
|
|
ListView_SetImageList(m_hList, m_ilSmall, LVSIL_SMALL);
|
|
ListView_SetImageList(m_hList, m_ilLarge, LVSIL_NORMAL);
|
|
SendMessage(m_hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_LABELTIP);
|
|
|
|
GetWindowRect(GetDlgItem(m_hwndDlg, IDC_STATIC1), &rect);
|
|
MapWindowPoints(NULL , m_hwndDlg, (LPPOINT) &rect , 2);
|
|
|
|
TBBUTTON rgButtons[3];
|
|
rgButtons[0].iBitmap = 0;
|
|
rgButtons[0].idCommand = ID_BACKBUTTON;
|
|
rgButtons[0].fsState = 0; // this button will be disabled by
|
|
// default and only enabled when there
|
|
// is something to back up to
|
|
//rgButtons[0].fsState = PAGETYPE_ALL == m_dwPageType ? 0 : TBSTATE_ENABLED;
|
|
rgButtons[0].fsStyle = TBSTYLE_BUTTON;
|
|
rgButtons[0].dwData = 0;
|
|
rgButtons[0].iString = 0;
|
|
|
|
rgButtons[1].iBitmap = 1;
|
|
rgButtons[1].idCommand = ID_NEWFOLDER;
|
|
rgButtons[1].fsStyle = TBSTYLE_BUTTON;
|
|
rgButtons[1].dwData = 0;
|
|
rgButtons[1].iString = 0;
|
|
|
|
if (PAGETYPE_ALL != m_dwPageType)
|
|
{
|
|
if (m_pGBI->dwFlags & GPO_BROWSE_DISABLENEW)
|
|
{
|
|
rgButtons[1].fsState = 0;
|
|
}
|
|
else
|
|
{
|
|
rgButtons[1].fsState = TBSTATE_ENABLED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rgButtons[1].fsState =TBSTATE_ENABLED;
|
|
}
|
|
|
|
rgButtons[2].iBitmap = 2;
|
|
rgButtons[2].idCommand = ID_ROTATEVIEW;
|
|
rgButtons[2].fsState = TBSTATE_ENABLED ;
|
|
rgButtons[2].fsStyle = TBSTYLE_DROPDOWN;
|
|
rgButtons[2].dwData = 0;
|
|
rgButtons[2].iString = 0;
|
|
m_toolbar = CreateToolbarEx(m_hwndDlg,
|
|
WS_CHILD | WS_VISIBLE | CCS_NODIVIDER | CCS_NORESIZE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
|
|
IDR_TOOLBAR1,
|
|
4,
|
|
g_hInstance,
|
|
IDR_TOOLBAR1,
|
|
rgButtons,
|
|
3,
|
|
BUTTONSIZE,
|
|
BUTTONSIZE,
|
|
BUTTONSIZE,
|
|
BUTTONSIZE,
|
|
sizeof(TBBUTTON));
|
|
SendMessage(m_toolbar, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
|
|
MoveWindow(m_toolbar, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, FALSE);
|
|
|
|
// Don't need to call Refresh in any of these because we're calling it in
|
|
// OnComboChange().
|
|
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
FillDomainList();
|
|
SetInitialOU();
|
|
// RefreshDomains();
|
|
break;
|
|
case PAGETYPE_SITES:
|
|
SendMessage(m_hCombo, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0);
|
|
FillSitesList();
|
|
// RefreshSites();
|
|
break;
|
|
default:
|
|
case PAGETYPE_ALL:
|
|
SendMessage(m_hCombo, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0);
|
|
FillDomainList();
|
|
// RefreshAll();
|
|
break;
|
|
}
|
|
|
|
SetButtonState();
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
BOOL CBrowserPP::DoBackButton()
|
|
{
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if (iIndex == CB_ERR)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::DoBackButton: No object selected.")));
|
|
return FALSE;
|
|
}
|
|
|
|
LOOKDATA * pdata = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdata)
|
|
{
|
|
if (pdata->pParent)
|
|
{
|
|
// if this item has a parent then select it
|
|
SendMessage(m_hCombo, CB_SELECTSTRING, (WPARAM)-1, (LPARAM) (LPCTSTR) pdata->pParent);
|
|
|
|
// force everything to refresh
|
|
OnComboChange();
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CBrowserPP::DeleteGPO()
|
|
{
|
|
BOOL fSucceeded = FALSE;
|
|
BOOL fRemoveListEntry = FALSE;
|
|
|
|
int index = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
|
|
if (-1 == index)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LVITEM item;
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = index;
|
|
ListView_GetItem(m_hList, &item);
|
|
MYLISTEL * pel = (MYLISTEL *)item.lParam;
|
|
LPGROUPPOLICYOBJECT pGPO = NULL;
|
|
HRESULT hr;
|
|
WCHAR szBuffer[100];
|
|
WCHAR szConfirm[MAX_FRIENDLYNAME + 100];
|
|
WCHAR szTitle[100];
|
|
|
|
|
|
if (pel->nType != ITEMTYPE_GPO)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
LoadString(g_hInstance, IDS_CONFIRMTITLE, szTitle, 100);
|
|
LoadString(g_hInstance, IDS_DELETECONFIRM, szBuffer, 100);
|
|
|
|
(void) StringCchPrintf (szConfirm, ARRAYSIZE(szConfirm), szBuffer, pel->szName);
|
|
|
|
if (IDNO == MessageBox(m_hwndDlg, szConfirm, szTitle, MB_YESNO | MB_ICONEXCLAMATION))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
// If we're on any page other than the "All" page then we need to break
|
|
// the association before we can delete the object.
|
|
if (m_dwPageType != PAGETYPE_ALL)
|
|
{
|
|
// break the association
|
|
LPOLESTR szContainer = GetCurrentObject();
|
|
if (szContainer)
|
|
{
|
|
DeleteLink(pel->szData, szContainer);
|
|
delete [] szContainer;
|
|
}
|
|
}
|
|
|
|
hr = CoCreateInstance(CLSID_GroupPolicyObject, NULL,
|
|
CLSCTX_SERVER, IID_IGroupPolicyObject,
|
|
(void **)&pGPO);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CoCreateInstance failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
|
|
// open GPO object without opening registry data
|
|
hr = pGPO->OpenDSGPO(pel->szData, 0);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDDS);
|
|
DebugMsg((DM_WARNING, TEXT("OpenDSGPO failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
// delete it
|
|
hr = pGPO->Delete();
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDDELETE);
|
|
DebugMsg((DM_WARNING, TEXT("Delete failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
fRemoveListEntry = TRUE;
|
|
|
|
Done:
|
|
if (pGPO)
|
|
{
|
|
pGPO->Release();
|
|
}
|
|
|
|
|
|
// remove the list entry
|
|
if (fRemoveListEntry)
|
|
fSucceeded = ListView_DeleteItem(m_hList, index);
|
|
CleanUp:
|
|
|
|
return fSucceeded;
|
|
}
|
|
|
|
BOOL CBrowserPP::DoNewGPO()
|
|
{
|
|
BOOL fSucceeded = FALSE;
|
|
HRESULT hr;
|
|
LPGROUPPOLICYOBJECT pGPO = NULL;
|
|
BOOL fEdit = FALSE;
|
|
MYLISTEL * pel = NULL;
|
|
LPOLESTR szObject = GetCurrentObject();
|
|
LPOLESTR szDomain = GetCurrentDomain();
|
|
INT index = -1;
|
|
int cch = 0;
|
|
LPTSTR szFullPath = NULL;
|
|
LPTSTR szServerName = NULL;
|
|
DWORD dwOptions = 0;
|
|
|
|
|
|
if (NULL == szDomain)
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
if (NULL == szObject)
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
|
|
pel = new MYLISTEL;
|
|
if (NULL == pel)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::DoNewGPO failed to allocate memory for GPO name")));
|
|
goto Done;
|
|
}
|
|
pel->bDisabled = FALSE;
|
|
pel->szData = NULL;
|
|
pel->szName = new OLECHAR[MAX_FRIENDLYNAME];
|
|
if (NULL == pel->szName)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::DoNewGPO failed to allocate memory for GPO name")));
|
|
goto Done;
|
|
}
|
|
|
|
GetNewGPODisplayName (pel->szName, MAX_FRIENDLYNAME);
|
|
|
|
pel->nType = ITEMTYPE_GPO;
|
|
|
|
// Create a new GPO named "New Group Policy Object"
|
|
|
|
//
|
|
// Create a new GPO object to work with
|
|
//
|
|
|
|
hr = CoCreateInstance (CLSID_GroupPolicyObject, NULL,
|
|
CLSCTX_SERVER, IID_IGroupPolicyObject,
|
|
(void**)&pGPO);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CoCreateInstance failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Open the requested object without mounting the registry
|
|
//
|
|
#if FGPO_SUPPORT
|
|
if (IsCurrentObjectAForest())
|
|
{
|
|
dwOptions = GPO_OPEN_FOREST;
|
|
}
|
|
#endif
|
|
hr = pGPO->New(szDomain, pel->szName, dwOptions);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDNEW);
|
|
DebugMsg((DM_WARNING, TEXT("Failed to create GPO object with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
// continue to try to allocate memory until either a big enough buffer is
|
|
// created to load the GPO path or we run out of memory
|
|
pel->szData = NULL;
|
|
do
|
|
{
|
|
if (pel->szData)
|
|
{
|
|
delete [] pel->szData;
|
|
}
|
|
cch += MAX_PATH;
|
|
pel->szData = new OLECHAR[cch];
|
|
if (NULL == pel->szData)
|
|
{
|
|
}
|
|
hr = pGPO->GetPath(pel->szData, cch);
|
|
} while (hr == E_OUTOFMEMORY);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("Failed to get GPO object path with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
|
|
}
|
|
|
|
szServerName = ExtractServerName(szDomain);
|
|
szFullPath = MakeFullPath(pel->szData, szServerName);
|
|
if (szFullPath)
|
|
{
|
|
ULONG ulNoChars = wcslen(szFullPath) + 1;
|
|
|
|
delete [] pel->szData;
|
|
pel->szData = new OLECHAR[ulNoChars];
|
|
if (NULL == pel->szData)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::DoNewGPO failed to allocate memory for GPO path")));
|
|
goto Done;
|
|
}
|
|
|
|
hr = StringCchCopy(pel->szData, ulNoChars, szFullPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
|
|
|
|
if (m_dwPageType != PAGETYPE_ALL)
|
|
{
|
|
// If we're not on the "All" page then we need to create a link.
|
|
CreateLink(pel->szData, szObject);
|
|
}
|
|
|
|
// Add the entry to the list view
|
|
|
|
index = AddElement(pel, -1);
|
|
fSucceeded = index != -1;
|
|
|
|
// It's been added so now we need to make sure we don't delete it below
|
|
pel = NULL;
|
|
|
|
// Record that we got this far
|
|
fEdit = TRUE;
|
|
|
|
Done:
|
|
if (pel)
|
|
{
|
|
if (pel->szData)
|
|
{
|
|
delete [] pel->szData;
|
|
}
|
|
if (pel->szName)
|
|
{
|
|
delete [] pel->szName;
|
|
}
|
|
delete pel;
|
|
}
|
|
if (pGPO)
|
|
pGPO->Release();
|
|
|
|
if (fEdit)
|
|
{
|
|
// Now trigger an edit of the entry
|
|
SetFocus(m_hList);
|
|
ListView_EditLabel(m_hList, index);
|
|
|
|
}
|
|
|
|
if (szServerName)
|
|
LocalFree(szServerName);
|
|
if (szFullPath)
|
|
LocalFree(szFullPath);
|
|
if (szDomain)
|
|
delete [] szDomain;
|
|
if (szObject)
|
|
delete [] szObject;
|
|
|
|
return fSucceeded;
|
|
}
|
|
|
|
BOOL CBrowserPP::CreateLink(LPOLESTR szObject, LPOLESTR szContainer)
|
|
{
|
|
HRESULT hr = CreateGPOLink(szObject, szContainer, FALSE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDLINK);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CBrowserPP::DeleteLink(LPOLESTR szObject, LPOLESTR szContainer)
|
|
{
|
|
HRESULT hr = DeleteGPOLink(szObject, szContainer);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDUNLINK);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CBrowserPP::DoRotateView()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
DWORD dw = dwStyle & LVS_TYPEMASK;
|
|
switch (dw)
|
|
{
|
|
case LVS_ICON:
|
|
dw = LVS_SMALLICON;
|
|
break;
|
|
case LVS_SMALLICON:
|
|
dw = LVS_LIST;
|
|
break;
|
|
case LVS_REPORT:
|
|
dw = LVS_ICON;
|
|
break;
|
|
case LVS_LIST:
|
|
default:
|
|
dw = LVS_REPORT;
|
|
break;
|
|
}
|
|
dwStyle -= dwStyle & LVS_TYPEMASK;
|
|
dwStyle += dw;
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle);
|
|
return TRUE;
|
|
}
|
|
|
|
void CBrowserPP::OnDetails()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
dwStyle -= dwStyle & LVS_TYPEMASK;
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle + LVS_REPORT);
|
|
}
|
|
|
|
void CBrowserPP::OnList()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
dwStyle -= dwStyle & LVS_TYPEMASK;
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle + LVS_LIST);
|
|
}
|
|
|
|
void CBrowserPP::OnLargeicons()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
dwStyle -= dwStyle & LVS_TYPEMASK;
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle + LVS_ICON);
|
|
|
|
}
|
|
|
|
void CBrowserPP::OnSmallicons()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
dwStyle -= dwStyle & LVS_TYPEMASK;
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle + LVS_SMALLICON);
|
|
}
|
|
|
|
void CBrowserPP::OnContextMenu(LPARAM lParam)
|
|
{
|
|
int i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
|
|
RECT rc;
|
|
POINT pt;
|
|
pt.x = ((int)(short)LOWORD(lParam));
|
|
pt.y = ((int)(short)HIWORD(lParam));
|
|
|
|
GetWindowRect (GetDlgItem (m_hwndDlg, IDC_LIST1), &rc);
|
|
|
|
if (!PtInRect (&rc, pt))
|
|
{
|
|
if ((lParam == (LPARAM) -1) && (i >= 0))
|
|
{
|
|
rc.left = LVIR_SELECTBOUNDS;
|
|
SendMessage (m_hList, LVM_GETITEMRECT, i, (LPARAM) &rc);
|
|
|
|
pt.x = rc.left + 8;
|
|
pt.y = rc.top + ((rc.bottom - rc.top) / 2);
|
|
|
|
ClientToScreen (m_hList, &pt);
|
|
}
|
|
else
|
|
{
|
|
pt.x = rc.left + ((rc.right - rc.left) / 2);
|
|
pt.y = rc.top + ((rc.bottom - rc.top) / 2);
|
|
}
|
|
}
|
|
|
|
|
|
// get the popup menu
|
|
HMENU hPopup;
|
|
hPopup = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_LISTMENU));
|
|
HMENU hSubMenu = GetSubMenu(hPopup, 0);
|
|
|
|
if (i >= 0)
|
|
{
|
|
// item selected
|
|
|
|
// figure out what type it is
|
|
LVITEM item;
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = i;
|
|
ListView_GetItem(m_hList, &item);
|
|
MYLISTEL * pel = (MYLISTEL *)item.lParam;
|
|
|
|
// get rid of the view menu and separator
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
// get rid of the arrange and line-up items
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
|
|
// get rid of the "new" menu item
|
|
RemoveMenu(hSubMenu, ID_NEW, MF_BYCOMMAND);
|
|
switch (pel->nType)
|
|
{
|
|
case ITEMTYPE_GPO:
|
|
if (pel->bDisabled)
|
|
{
|
|
// disable edit, rename, delete
|
|
EnableMenuItem(hSubMenu, ID_EDIT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hSubMenu, ID_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hSubMenu, ID_DELETE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
break;
|
|
default:
|
|
case ITEMTYPE_FOREST:
|
|
case ITEMTYPE_SITE:
|
|
case ITEMTYPE_DOMAIN:
|
|
case ITEMTYPE_OU:
|
|
// remove the edit menu item and the separator
|
|
RemoveMenu(hSubMenu, ID_EDIT, MF_BYCOMMAND);
|
|
RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
|
|
// disable rename, delete and properties
|
|
EnableMenuItem(hSubMenu, ID_RENAME, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hSubMenu, ID_DELETE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
EnableMenuItem(hSubMenu, ID_PROPERTIES, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no item selected
|
|
|
|
// get rid of the edit menu item
|
|
RemoveMenu(hSubMenu, ID_EDIT, MF_BYCOMMAND);
|
|
|
|
// get rid of the delete and rename items
|
|
RemoveMenu(hSubMenu, ID_DELETE, MF_BYCOMMAND);
|
|
RemoveMenu(hSubMenu, ID_RENAME, MF_BYCOMMAND);
|
|
|
|
|
|
if (PAGETYPE_ALL != m_dwPageType)
|
|
{
|
|
if (m_pGBI->dwFlags & GPO_BROWSE_DISABLENEW)
|
|
{
|
|
// get rid of the "new" menu item
|
|
RemoveMenu(hSubMenu, ID_NEW, MF_BYCOMMAND);
|
|
RemoveMenu(hSubMenu, 4, MF_BYPOSITION);
|
|
}
|
|
}
|
|
|
|
RemoveMenu(hSubMenu, (GetMenuItemCount(hSubMenu) - 1), MF_BYPOSITION);
|
|
RemoveMenu(hSubMenu, (GetMenuItemCount(hSubMenu) - 1), MF_BYPOSITION);
|
|
|
|
|
|
// set view radio button
|
|
UINT ui = ID_LIST;
|
|
|
|
DWORD dw = GetWindowLong(m_hList, GWL_STYLE) & LVS_TYPEMASK;
|
|
|
|
if (dw == LVS_ICON || dw == LVS_SMALLICON)
|
|
{
|
|
// Auto-Arrange means something in these views so we need to enable it
|
|
EnableMenuItem(hSubMenu, ID_ARRANGE_AUTO, MF_BYCOMMAND | MF_ENABLED);
|
|
// also need to make sure it's set correctly
|
|
if (LVS_AUTOARRANGE == (GetWindowLong(m_hList, GWL_STYLE) & LVS_AUTOARRANGE))
|
|
CheckMenuItem(hSubMenu, ID_ARRANGE_AUTO, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
switch (dw)
|
|
{
|
|
case LVS_ICON:
|
|
ui = ID_LARGEICONS;
|
|
break;
|
|
case LVS_SMALLICON:
|
|
ui = ID_SMALLICONS;
|
|
break;
|
|
case LVS_REPORT:
|
|
ui = ID_DETAILS;
|
|
break;
|
|
case LVS_LIST:
|
|
default:
|
|
ui = ID_LIST;
|
|
break;
|
|
}
|
|
CheckMenuRadioItem(hSubMenu, ui, ui, ui, MF_BYCOMMAND);
|
|
|
|
}
|
|
TrackPopupMenu(hSubMenu,
|
|
TPM_LEFTALIGN,
|
|
pt.x, pt.y,
|
|
0,
|
|
m_hwndDlg,
|
|
NULL);
|
|
DestroyMenu(hPopup);
|
|
}
|
|
|
|
|
|
void CBrowserPP::OnArrangeAuto()
|
|
{
|
|
DWORD dwStyle = GetWindowLong(m_hList, GWL_STYLE);
|
|
if (LVS_AUTOARRANGE == (dwStyle & LVS_AUTOARRANGE))
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle - LVS_AUTOARRANGE);
|
|
else
|
|
SetWindowLong(m_hList, GWL_STYLE, dwStyle + LVS_AUTOARRANGE);
|
|
}
|
|
|
|
int CALLBACK CompareName(LPARAM lParam1, LPARAM lParam2, LPARAM lParamsort)
|
|
{
|
|
MYLISTEL * pel1 = (MYLISTEL *)lParam1;
|
|
MYLISTEL * pel2 = (MYLISTEL *)lParam2;
|
|
return _wcsicmp(pel1->szName, pel2->szName);
|
|
}
|
|
|
|
int CALLBACK CompareType(LPARAM lParam1, LPARAM lParam2, LPARAM lParamsort)
|
|
{
|
|
MYLISTEL * pel1 = (MYLISTEL *)lParam1;
|
|
MYLISTEL * pel2 = (MYLISTEL *)lParam2;
|
|
return pel1->nType - pel2->nType;
|
|
}
|
|
|
|
void CBrowserPP::OnArrangeByname()
|
|
{
|
|
ListView_SortItems(m_hList, CompareName, 0);
|
|
}
|
|
|
|
void CBrowserPP::OnArrangeBytype()
|
|
{
|
|
ListView_SortItems(m_hList, CompareType, 0);
|
|
}
|
|
|
|
void CBrowserPP::OnDelete()
|
|
{
|
|
DeleteGPO();
|
|
}
|
|
|
|
void CBrowserPP::OnEdit()
|
|
{
|
|
INT i;
|
|
HRESULT hr;
|
|
LVITEM item;
|
|
MYLISTEL * pel;
|
|
LPTSTR lpDomainName;
|
|
LPOLESTR pszDomain;
|
|
|
|
|
|
|
|
i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
|
|
|
|
if (i >= 0)
|
|
{
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = i;
|
|
|
|
ListView_GetItem(m_hList, &item);
|
|
|
|
pel = (MYLISTEL *)item.lParam;
|
|
|
|
if (pel->nType == ITEMTYPE_GPO)
|
|
{
|
|
//
|
|
// Get the friendly domain name
|
|
//
|
|
|
|
pszDomain = GetDomainFromLDAPPath(pel->szData);
|
|
|
|
if (!pszDomain)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::OnEdit: Failed to get domain name")));
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert LDAP to dot (DN) style
|
|
//
|
|
|
|
hr = ConvertToDotStyle (pszDomain, &lpDomainName);
|
|
|
|
delete [] pszDomain;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CGroupPolicyObject::CreatePropertyPages: Failed to convert domain name with 0x%x"), hr));
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if the GPO is in the same domain as GPM is focused on
|
|
//
|
|
|
|
if (!lstrcmpi(lpDomainName, m_szDomainName))
|
|
{
|
|
SpawnGPE (pel->szData, GPHintUnknown, m_szServerName, m_hwndDlg);
|
|
}
|
|
else
|
|
{
|
|
SpawnGPE (pel->szData, GPHintUnknown, NULL, m_hwndDlg);
|
|
}
|
|
|
|
|
|
LocalFree (lpDomainName);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnNew()
|
|
{
|
|
DoNewGPO();
|
|
}
|
|
|
|
void CBrowserPP::OnProperties()
|
|
{
|
|
INT iIndex;
|
|
LVITEM item;
|
|
HRESULT hr;
|
|
LPGROUPPOLICYOBJECT pGPO;
|
|
HPROPSHEETPAGE *hPages;
|
|
UINT i, uPageCount;
|
|
PROPSHEETHEADER psh;
|
|
|
|
iIndex = ListView_GetNextItem(m_hList, -1, LVNI_ALL | LVNI_SELECTED);
|
|
if (iIndex >= 0)
|
|
{
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = iIndex;
|
|
ListView_GetItem(m_hList, &item);
|
|
|
|
MYLISTEL * pel = (MYLISTEL *)item.lParam;
|
|
if (pel && pel->nType == ITEMTYPE_GPO)
|
|
{
|
|
hr = CoCreateInstance (CLSID_GroupPolicyObject, NULL,
|
|
CLSCTX_SERVER, IID_IGroupPolicyObject,
|
|
(void**)&pGPO);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::OnProperties: CoCreateInstance failed with 0x%x\r\n"), hr));
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the requested object without mounting the registry
|
|
//
|
|
|
|
hr = pGPO->OpenDSGPO(pel->szData, 0);
|
|
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
|
|
{
|
|
hr = pGPO->OpenDSGPO(pel->szData, GPO_OPEN_READ_ONLY);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::OnProperties: Failed to open GPO object with 0x%x\r\n"), hr));
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDDS);
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Ask the GPO for the property sheet pages
|
|
//
|
|
|
|
hr = pGPO->GetPropertySheetPages (&hPages, &uPageCount);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::OnProperties: Failed to query property sheet pages with 0x%x."), hr));
|
|
pGPO->Release();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Display the property sheet
|
|
//
|
|
|
|
ZeroMemory (&psh, sizeof(psh));
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = PSH_PROPTITLE;
|
|
psh.hwndParent = m_hwndDlg;
|
|
psh.hInstance = g_hInstance;
|
|
psh.pszCaption = pel->szName;
|
|
psh.nPages = uPageCount;
|
|
psh.phpage = hPages;
|
|
|
|
PropertySheet (&psh);
|
|
|
|
LocalFree (hPages);
|
|
pGPO->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnRefresh()
|
|
{
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
RefreshDomains();
|
|
break;
|
|
case PAGETYPE_SITES:
|
|
RefreshSites();
|
|
break;
|
|
default:
|
|
case PAGETYPE_ALL:
|
|
RefreshAll();
|
|
break;
|
|
}
|
|
|
|
SetButtonState();
|
|
}
|
|
|
|
void CBrowserPP::OnRename()
|
|
{
|
|
//
|
|
// alow the rename only if it is possible to rename
|
|
//
|
|
|
|
int i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
|
|
if (i >= 0)
|
|
{
|
|
// item selected
|
|
|
|
// figure out what type it is
|
|
LVITEM item;
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = i;
|
|
ListView_GetItem(m_hList, &item);
|
|
MYLISTEL * pel = (MYLISTEL *)item.lParam;
|
|
|
|
if ((pel) && (pel->nType == ITEMTYPE_GPO)
|
|
&& (!(pel->bDisabled))) {
|
|
ListView_EditLabel(m_hList, ListView_GetNextItem(m_hList, -1, LVNI_SELECTED));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnTopLineupicons()
|
|
{
|
|
ListView_Arrange(m_hList, LVA_SNAPTOGRID);
|
|
}
|
|
|
|
void CBrowserPP::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
|
|
// Return FALSE to enable editing, TRUE to disable it
|
|
MYLISTEL * pel = (MYLISTEL *)pDispInfo->item.lParam;
|
|
*pResult = (pel->nType == ITEMTYPE_GPO) ? FALSE : TRUE;
|
|
}
|
|
|
|
void CBrowserPP::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
*pResult = FALSE;
|
|
LPGROUPPOLICYOBJECT pGPO = NULL;
|
|
HRESULT hr;
|
|
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
|
|
|
|
if (NULL == pDispInfo->item.pszText)
|
|
{
|
|
// user cancelled edit
|
|
return;
|
|
}
|
|
|
|
if (TEXT('\0') == (*pDispInfo->item.pszText))
|
|
{
|
|
// user entered an empty string
|
|
return;
|
|
}
|
|
|
|
|
|
MYLISTEL * pel = (MYLISTEL *)pDispInfo->item.lParam;
|
|
if (0 ==wcscmp(pDispInfo->item.pszText, pel->szName))
|
|
{
|
|
// user didn't change anything
|
|
return;
|
|
}
|
|
|
|
LPWSTR sz = new WCHAR[wcslen(pDispInfo->item.pszText)+1];
|
|
|
|
if (NULL == sz)
|
|
{
|
|
*pResult = FALSE;
|
|
goto Done;
|
|
return;
|
|
}
|
|
|
|
hr = CoCreateInstance(CLSID_GroupPolicyObject, NULL,
|
|
CLSCTX_SERVER, IID_IGroupPolicyObject,
|
|
(void **)&pGPO);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CoCreateInstance failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
|
|
// open GPO object without opening registry data
|
|
hr = pGPO->OpenDSGPO(pel->szData, 0);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDDS);
|
|
DebugMsg((DM_WARNING, TEXT("OpenDSGPO failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
// rename it
|
|
hr = pGPO->SetDisplayName(pDispInfo->item.pszText);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDSETNAME);
|
|
DebugMsg((DM_WARNING, TEXT("SetDisplayName failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
// requery for the name
|
|
hr = pGPO->GetDisplayName(sz, (wcslen(pDispInfo->item.pszText)+1));
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(m_hwndDlg, hr, IDS_FAILEDSETNAME);
|
|
DebugMsg((DM_WARNING, TEXT("GetDisplayName failed with 0x%x\r\n"), hr));
|
|
goto Done;
|
|
}
|
|
|
|
delete [] pel->szName;
|
|
pel->szName = sz;
|
|
sz = NULL;
|
|
|
|
// return TRUE to accept the rename, FALSE to reject it
|
|
|
|
*pResult = TRUE;
|
|
PostMessage (m_hwndDlg, WM_REFRESHDISPLAY, (WPARAM) pDispInfo->item.iItem, 0);
|
|
|
|
Done:
|
|
if (sz)
|
|
{
|
|
delete [] sz;
|
|
}
|
|
|
|
if (pGPO)
|
|
{
|
|
pGPO->Release();
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnBegindragList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CBrowserPP::OnDeleteitemList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
MYLISTEL * pel = (MYLISTEL *)pNMListView->lParam;
|
|
if (pel)
|
|
{
|
|
if (pel->szName)
|
|
{
|
|
delete [] pel->szName;
|
|
}
|
|
if (pel->szData)
|
|
{
|
|
delete [] pel->szData;
|
|
}
|
|
delete pel;
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CBrowserPP::OnDoubleclickList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
|
|
if (pNMListView->iItem >= 0)
|
|
{
|
|
// item selected
|
|
PropSheet_PressButton(GetParent(m_hwndDlg), PSBTN_OK);
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CBrowserPP::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
|
|
|
switch (pNMListView->iSubItem)
|
|
{
|
|
case 0:
|
|
ListView_SortItems(m_hList, CompareName, 0);
|
|
break;
|
|
case 1:
|
|
default:
|
|
ListView_SortItems(m_hList, CompareType, 0);
|
|
break;
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CBrowserPP::OnKeyDownList(NMHDR * pNMHDR, LRESULT * pResult)
|
|
{
|
|
LV_KEYDOWN * pnkd = (LV_KEYDOWN *)pNMHDR;
|
|
|
|
switch (pnkd->wVKey)
|
|
{
|
|
case VK_F5:
|
|
OnRefresh();
|
|
break;
|
|
case VK_F2:
|
|
OnRename();
|
|
break;
|
|
case VK_DELETE:
|
|
OnDelete();
|
|
break;
|
|
|
|
case VK_BACK:
|
|
DoBackButton();
|
|
break;
|
|
|
|
case VK_RETURN:
|
|
OnProperties();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnItemChanged(NMHDR * pNMHDR, LRESULT * pResult)
|
|
{
|
|
SetButtonState();
|
|
}
|
|
|
|
void CBrowserPP::TrimComboBox()
|
|
{
|
|
LOOKDATA * pdataSelected = NULL;
|
|
int iCount;
|
|
|
|
// first check to see if something is selected
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
// something's selected, get a pointer to it's data
|
|
pdataSelected = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
|
|
// check if the user selected the same thing again
|
|
if (m_pPrevSel && (m_pPrevSel == pdataSelected))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if it has a parent then enable the back button
|
|
SendMessage(m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_BACKBUTTON, (LPARAM)MAKELONG(NULL != pdataSelected->pParent, 0));
|
|
}
|
|
|
|
// If the child of the selected object is an OU then delete all of it's children
|
|
// otherwise delete ALL OUs from the list.
|
|
|
|
if (pdataSelected)
|
|
{
|
|
if (pdataSelected->pChild)
|
|
{
|
|
if (ITEMTYPE_OU == pdataSelected->pChild->nType)
|
|
{
|
|
// delete all of its children
|
|
goto DeleteChildren;
|
|
}
|
|
}
|
|
}
|
|
|
|
iCount = (int)SendMessage(m_hCombo, CB_GETCOUNT, 0, 0);
|
|
iIndex = 0;
|
|
while (iIndex < iCount)
|
|
{
|
|
// find the first entry that has an OU for a child.
|
|
pdataSelected = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
|
|
if (pdataSelected)
|
|
{
|
|
if (pdataSelected->pChild)
|
|
{
|
|
if (ITEMTYPE_OU == pdataSelected->pChild->nType)
|
|
{
|
|
DeleteChildren:
|
|
LOOKDATA * pChild = pdataSelected->pChild;
|
|
pdataSelected->pChild = pChild->pSibling;
|
|
while (pChild)
|
|
{
|
|
iIndex = (int)SendMessage(m_hCombo, CB_FINDSTRING, iIndex, (LPARAM)(LPCTSTR*)pChild);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
pChild = pChild->pChild;
|
|
SendMessage(m_hCombo, CB_DELETESTRING, iIndex, 0);
|
|
}
|
|
else
|
|
{
|
|
pChild = NULL;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
iIndex++;
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::OnComboChange()
|
|
{
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
{
|
|
TrimComboBox();
|
|
}
|
|
// fall through to refresh the list view
|
|
case PAGETYPE_SITES:
|
|
case PAGETYPE_ALL:
|
|
default:
|
|
OnRefresh();
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL CBrowserPP::OnSetActive()
|
|
{
|
|
*m_ppActive = this;
|
|
OnRefresh();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CBrowserPP::OnApply()
|
|
{
|
|
if (*m_ppActive == (void *) this)
|
|
{
|
|
// perform the proper task on the selected item
|
|
int i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
|
|
if (i >= 0)
|
|
{
|
|
LVITEM item;
|
|
memset(&item, 0, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = i;
|
|
ListView_GetItem(m_hList, &item);
|
|
MYLISTEL * pel = (MYLISTEL *)item.lParam;
|
|
switch (pel->nType)
|
|
{
|
|
case ITEMTYPE_GPO:
|
|
m_pGBI->gpoType = GPOTypeDS;
|
|
wcsncpy(m_pGBI->lpDSPath, pel->szData, m_pGBI->dwDSPathSize);
|
|
if (m_pGBI->lpName)
|
|
{
|
|
wcsncpy(m_pGBI->lpName, pel->szName, m_pGBI->dwNameSize);
|
|
}
|
|
m_pGBI->gpoHint = GPHintUnknown;
|
|
break;
|
|
default:
|
|
case ITEMTYPE_FOREST:
|
|
case ITEMTYPE_SITE:
|
|
case ITEMTYPE_DOMAIN:
|
|
// change the focus
|
|
{
|
|
LOOKDATA * pdataSelected = NULL;
|
|
|
|
|
|
// first make sure something is selected
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
// something's selected, get a pointer to it's data
|
|
pdataSelected = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdataSelected)
|
|
{
|
|
// Now walk its children until we find a match
|
|
pdataSelected = pdataSelected->pChild;
|
|
while (pdataSelected)
|
|
{
|
|
if (0 == wcscmp(pdataSelected->szData, pel->szData))
|
|
{
|
|
iIndex = (int)SendMessage(m_hCombo, CB_FINDSTRING, iIndex, (LPARAM) (LPCTSTR)pdataSelected);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
SendMessage(m_hCombo, CB_SETCURSEL, iIndex, 0);
|
|
// Enable the back-button
|
|
SendMessage(m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_BACKBUTTON, (LPARAM) MAKELONG(TRUE, 0));
|
|
}
|
|
break;
|
|
}
|
|
pdataSelected = pdataSelected->pSibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
OnRefresh();
|
|
return FALSE; // don't allow propsheet to close
|
|
case ITEMTYPE_OU:
|
|
// Add the new object to combobox and change the focus.
|
|
{
|
|
LOOKDATA * pdataSelected = NULL;
|
|
|
|
|
|
// first make sure something is selected
|
|
int iIndex = (int)SendMessage (m_hCombo, CB_GETCURSEL, 0, 0);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
// something's selected, get a pointer to it's data
|
|
pdataSelected = (LOOKDATA *) SendMessage (m_hCombo, CB_GETITEMDATA, iIndex, 0);
|
|
if (pdataSelected)
|
|
{
|
|
LOOKDATA * pNew = new LOOKDATA;
|
|
if (pNew)
|
|
{
|
|
ULONG ulNoCharsName = wcslen(pel->szName)+1;
|
|
pNew->szName = new WCHAR[ulNoCharsName];
|
|
if (pNew->szName)
|
|
{
|
|
ULONG ulNoCharsData = wcslen(pel->szData)+1;
|
|
pNew->szData = new WCHAR[ulNoCharsData];
|
|
if (pNew->szData)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = StringCchCopy(pNew->szName, ulNoCharsName, pel->szName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
hr = StringCchCopy(pNew->szData, ulNoCharsData, pel->szData);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
pNew->nIndent = pdataSelected->nIndent + 1;
|
|
pNew->nType = ITEMTYPE_OU;
|
|
pNew->pParent = pdataSelected;
|
|
pNew->pSibling = pdataSelected->pChild;
|
|
pNew->pChild = NULL;
|
|
pdataSelected ->pChild = pNew;
|
|
SendMessage(m_hCombo, CB_INSERTSTRING, (WPARAM) iIndex + 1, (LPARAM) (LPCTSTR) pNew);
|
|
SendMessage(m_hCombo, CB_SETCURSEL, iIndex + 1, 0);
|
|
// Enable the back-button
|
|
SendMessage(m_toolbar, TB_ENABLEBUTTON, (WPARAM) ID_BACKBUTTON, (LPARAM) MAKELONG(TRUE, 0));
|
|
}
|
|
else
|
|
{
|
|
delete [] pNew->szName;
|
|
delete pNew;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pNew;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
OnRefresh();
|
|
return FALSE; // don't allow propsheet to close
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE; // don't allow propsheet to close
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CBrowserPP::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
m_hwndDlg = hwndDlg;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
return OnInitDialog();
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR pnmh = (LPNMHDR) lParam;
|
|
LRESULT lResult = 0;
|
|
|
|
switch (pnmh->code)
|
|
{
|
|
case NM_KEYDOWN:
|
|
{
|
|
LPNMKEY pnkd = (LPNMKEY)pnmh;
|
|
|
|
if (VK_F5 == pnkd->nVKey)
|
|
{
|
|
OnRefresh();
|
|
}
|
|
}
|
|
break;
|
|
case PSN_SETACTIVE:
|
|
OnSetActive();
|
|
break;
|
|
case PSN_APPLY:
|
|
lResult = OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
|
|
fReturn = TRUE;
|
|
break;
|
|
case NM_DBLCLK:
|
|
if (IDC_LIST1 == wParam)
|
|
{
|
|
OnDoubleclickList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
case LVN_BEGINLABELEDIT:
|
|
OnBeginlabeleditList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
break;
|
|
case LVN_ENDLABELEDIT:
|
|
OnEndlabeleditList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
break;
|
|
case LVN_BEGINDRAG:
|
|
OnBegindragList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
break;
|
|
case LVN_DELETEITEM:
|
|
OnDeleteitemList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
break;
|
|
case LVN_COLUMNCLICK:
|
|
OnColumnclickList(pnmh, &lResult);
|
|
fReturn = TRUE;
|
|
break;
|
|
case LVN_KEYDOWN:
|
|
OnKeyDownList(pnmh, &lResult);
|
|
break;
|
|
case LVN_ITEMCHANGED:
|
|
OnItemChanged(pnmh, &lResult);
|
|
break;
|
|
case TBN_DROPDOWN:
|
|
{
|
|
RECT r;
|
|
SendMessage(m_toolbar, TB_GETRECT, ((TBNOTIFY *)lParam)->iItem, (LPARAM)&r);
|
|
MapWindowPoints(m_toolbar, NULL, (POINT *)&r, 2);
|
|
HMENU hPopup;
|
|
hPopup = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_LISTMENU));
|
|
|
|
if ( ! hPopup )
|
|
{
|
|
break;
|
|
}
|
|
|
|
UINT ui = ID_LIST;
|
|
|
|
DWORD dw = GetWindowLong(m_hList, GWL_STYLE) & LVS_TYPEMASK;
|
|
switch (dw)
|
|
{
|
|
case LVS_ICON:
|
|
ui = ID_LARGEICONS;
|
|
break;
|
|
case LVS_SMALLICON:
|
|
ui = ID_SMALLICONS;
|
|
break;
|
|
case LVS_REPORT:
|
|
ui = ID_DETAILS;
|
|
break;
|
|
case LVS_LIST:
|
|
default:
|
|
ui = ID_LIST;
|
|
break;
|
|
}
|
|
HMENU hSubMenu = GetSubMenu(GetSubMenu(hPopup, 0), 0);
|
|
CheckMenuRadioItem(hSubMenu, ui, ui, ui, MF_BYCOMMAND);
|
|
TrackPopupMenu(hSubMenu,
|
|
TPM_LEFTALIGN,
|
|
r.left, r.bottom,
|
|
0,
|
|
m_hwndDlg,
|
|
&r);
|
|
fReturn = TRUE;
|
|
DestroyMenu(hPopup);
|
|
break;
|
|
}
|
|
break;
|
|
case TTN_GETDISPINFO:
|
|
{
|
|
LPNMTTDISPINFO pDI = (LPNMTTDISPINFO) lParam;
|
|
UINT id = 0;
|
|
|
|
if (pDI->hdr.idFrom == ID_BACKBUTTON)
|
|
id = IDS_TOOLTIP_BACK;
|
|
else if (pDI->hdr.idFrom == ID_NEWFOLDER)
|
|
id = IDS_TOOLTIP_NEW;
|
|
else if (pDI->hdr.idFrom == ID_ROTATEVIEW)
|
|
id = IDS_TOOLTIP_ROTATE;
|
|
|
|
if (id)
|
|
LoadString (g_hInstance, id, pDI->szText, 80);
|
|
else
|
|
pDI->szText[0] = TEXT('\0');
|
|
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
SetWindowLongPtr(m_hwndDlg, DWLP_MSGRESULT, lResult);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_COMBO1:
|
|
if (CBN_SELCHANGE == HIWORD(wParam))
|
|
{
|
|
OnComboChange();
|
|
}
|
|
break;
|
|
case ID_BACKBUTTON:
|
|
return DoBackButton();
|
|
case ID_NEWFOLDER:
|
|
return DoNewGPO();
|
|
case ID_ROTATEVIEW:
|
|
return DoRotateView();
|
|
case ID_DETAILS:
|
|
OnDetails();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_LIST:
|
|
OnList();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_LARGEICONS:
|
|
OnLargeicons();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_SMALLICONS:
|
|
OnSmallicons();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_ARRANGE_AUTO:
|
|
OnArrangeAuto();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_ARRANGE_BYNAME:
|
|
OnArrangeByname();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_ARRANGE_BYTYPE:
|
|
OnArrangeBytype();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_DELETE:
|
|
OnDelete();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_EDIT:
|
|
OnEdit();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_NEW:
|
|
OnNew();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_PROPERTIES:
|
|
OnProperties();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_REFRESH:
|
|
OnRefresh();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_RENAME:
|
|
OnRename();
|
|
fReturn = TRUE;
|
|
break;
|
|
case ID_TOP_LINEUPICONS:
|
|
OnTopLineupicons();
|
|
fReturn = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
fReturn = TRUE;
|
|
if ((HWND)wParam != m_toolbar)
|
|
{
|
|
if (GetDlgItem(hwndDlg, IDC_LIST1) == (HWND)wParam)
|
|
{
|
|
OnContextMenu(lParam);
|
|
}
|
|
else
|
|
{
|
|
// right mouse click
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
|
|
(ULONG_PTR) (LPSTR) aBrowserDomainHelpIds);
|
|
break;
|
|
|
|
case PAGETYPE_SITES:
|
|
WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
|
|
(ULONG_PTR) (LPSTR) aBrowserSiteHelpIds);
|
|
break;
|
|
|
|
case PAGETYPE_ALL:
|
|
WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
|
|
(ULONG_PTR) (LPSTR) aBrowserAllHelpIds);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_HELP:
|
|
// F1 help
|
|
if (((LPHELPINFO) lParam)->iCtrlId != IDR_TOOLBAR1)
|
|
{
|
|
switch (m_dwPageType)
|
|
{
|
|
case PAGETYPE_DOMAINS:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP,
|
|
(ULONG_PTR) (LPSTR) aBrowserDomainHelpIds);
|
|
break;
|
|
|
|
case PAGETYPE_SITES:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP,
|
|
(ULONG_PTR) (LPSTR) aBrowserSiteHelpIds);
|
|
break;
|
|
|
|
case PAGETYPE_ALL:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP,
|
|
(ULONG_PTR) (LPSTR) aBrowserAllHelpIds);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fReturn = TRUE;
|
|
break;
|
|
|
|
case WM_DRAWITEM:
|
|
if (IDC_COMBO1 == wParam)
|
|
{
|
|
DrawItem((LPDRAWITEMSTRUCT)lParam);
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
case WM_MEASUREITEM:
|
|
if (IDC_COMBO1 == wParam)
|
|
{
|
|
MeasureItem((LPMEASUREITEMSTRUCT)lParam);
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
case WM_COMPAREITEM:
|
|
if (IDC_COMBO1 == wParam)
|
|
{
|
|
int iReturn = CompareItem((LPCOMPAREITEMSTRUCT)lParam);
|
|
SetWindowLongPtr(m_hwndDlg, DWLP_MSGRESULT, iReturn);
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
case WM_DELETEITEM:
|
|
if (IDC_COMBO1 == wParam)
|
|
{
|
|
DeleteItem((LPDELETEITEMSTRUCT)lParam);
|
|
fReturn = TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_REFRESHDISPLAY:
|
|
{
|
|
MYLISTEL * pel;
|
|
LVITEM item;
|
|
|
|
|
|
ZeroMemory (&item, sizeof(item));
|
|
item.mask = LVIF_PARAM;
|
|
item.iItem = (INT) wParam;
|
|
|
|
if (ListView_GetItem(m_hList, &item))
|
|
{
|
|
pel = (MYLISTEL *)item.lParam;
|
|
ListView_SetItemText(m_hList, (INT)wParam, 0, pel->szName);
|
|
}
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return fReturn;
|
|
}
|
|
|
|
void CBrowserPP::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
|
{
|
|
// DRAWITEMSTRUCT:
|
|
// UINT CtlType // type of the control
|
|
// UINT CtlID; // ID of the control
|
|
// UINT itemID; // index of the item
|
|
// UINT itemAction;
|
|
// UINT itemState;
|
|
// HWND hwndItem;
|
|
// HDC hDC;
|
|
// RECT rcItem;
|
|
// DWORD itemData; // user-defined data
|
|
|
|
if (-1 != lpDrawItemStruct->itemID)
|
|
{
|
|
LOOKDATA * pdata = (LOOKDATA *)lpDrawItemStruct->itemData;
|
|
POINT pt;
|
|
INT iIndex;
|
|
|
|
if (pdata->nType == ITEMTYPE_FOREST)
|
|
{
|
|
iIndex = 10;
|
|
}
|
|
else if (pdata->nType == ITEMTYPE_SITE)
|
|
{
|
|
iIndex = 6;
|
|
}
|
|
else if (pdata->nType == ITEMTYPE_DOMAIN)
|
|
{
|
|
iIndex = 7;
|
|
}
|
|
else
|
|
{
|
|
iIndex = 0;
|
|
}
|
|
|
|
pt.x = lpDrawItemStruct->rcItem.left;
|
|
BOOL fSelected = ODS_SELECTED == (ODS_SELECTED & lpDrawItemStruct->itemState);
|
|
BOOL fComboBoxEdit = ODS_COMBOBOXEDIT != (ODS_COMBOBOXEDIT & lpDrawItemStruct->itemState);
|
|
if (fComboBoxEdit)
|
|
pt.x += (INDENT * pdata->nIndent);
|
|
pt.y = lpDrawItemStruct->rcItem.top;
|
|
ImageList_Draw(m_ilSmall, iIndex, lpDrawItemStruct->hDC, pt.x, pt.y, fSelected ? ILD_SELECTED : ILD_NORMAL);
|
|
SIZE size;
|
|
GetTextExtentPoint32(lpDrawItemStruct->hDC, pdata->szName, wcslen(pdata->szName), &size);
|
|
COLORREF crBk;
|
|
COLORREF crText;
|
|
if (fSelected)
|
|
{
|
|
crBk = GetBkColor(lpDrawItemStruct->hDC);
|
|
crText = GetTextColor(lpDrawItemStruct->hDC);
|
|
SetBkColor(lpDrawItemStruct->hDC, GetSysColor(COLOR_HIGHLIGHT));
|
|
SetTextColor(lpDrawItemStruct->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
}
|
|
// NOTE, SMALLICONSIZE + 1 is used here to ensure it rounds UP
|
|
// instead of down when centering the text. (It looks better this
|
|
// way.)
|
|
// Adding 18 to the x coord spaces us past the icon.
|
|
ExtTextOut(lpDrawItemStruct->hDC, pt.x + (SMALLICONSIZE + 2), pt.y + (((SMALLICONSIZE + 1) - size.cy) / 2), ETO_CLIPPED, &lpDrawItemStruct->rcItem, pdata->szName, wcslen(pdata->szName), NULL);
|
|
if (fSelected)
|
|
{
|
|
SetBkColor(lpDrawItemStruct->hDC, crBk);
|
|
SetTextColor(lpDrawItemStruct->hDC, crText);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBrowserPP::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
|
|
{
|
|
// MEASUREITEMSTRUCT:
|
|
// UINT CtlType // type of the control
|
|
// UINT CtlID; // ID of the control
|
|
// UINT itemID; // index of the item
|
|
// UINT itemWidth; // width of item in pixels
|
|
// UINT itemHeight; // height of item in pixels
|
|
// DWORD itemData; // user-defined data
|
|
|
|
lpMeasureItemStruct->itemHeight = SMALLICONSIZE;
|
|
}
|
|
|
|
int CBrowserPP::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
|
|
{
|
|
// COMPAREITEMSTRUCT:
|
|
// UINT CtlType // type of the control
|
|
// UINT CtlID; // ID of the control
|
|
// HWND hwndItem; // handle of the control
|
|
// UINT itemID; // index of the item
|
|
// DWORD itemData1; // user-defined data
|
|
// UINT itemID2; // index of the second item
|
|
// DWORD itemData2; // user-defined data
|
|
|
|
// I'm not doing any sorting.
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CBrowserPP::DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
|
|
{
|
|
LOOKDATA * pdata = (LOOKDATA *)lpDeleteItemStruct->itemData;
|
|
if (NULL != pdata)
|
|
{
|
|
if (NULL != pdata->szName)
|
|
{
|
|
delete [] pdata->szName;
|
|
}
|
|
if (NULL != pdata->szData)
|
|
{
|
|
delete [] pdata->szData;
|
|
}
|
|
delete pdata;
|
|
}
|
|
}
|
|
|
|
LPTSTR CBrowserPP::GetFullPath (LPTSTR lpPath, HWND hParent)
|
|
{
|
|
LPTSTR lpFullPath = NULL, lpDomainName = NULL;
|
|
LPTSTR lpGPDCName;
|
|
LPOLESTR pszDomain;
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
//
|
|
// Get the friendly domain name
|
|
//
|
|
|
|
pszDomain = GetDomainFromLDAPPath(lpPath);
|
|
|
|
if (!pszDomain)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetFullPath: Failed to get domain name")));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert LDAP to dot (DN) style
|
|
//
|
|
|
|
hr = ConvertToDotStyle (pszDomain, &lpDomainName);
|
|
|
|
delete [] pszDomain;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetFullPath: Failed to convert domain name with 0x%x"), hr));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
if (!lstrcmpi(lpDomainName, m_szDomainName))
|
|
{
|
|
|
|
//
|
|
// Make the full path
|
|
//
|
|
|
|
lpFullPath = MakeFullPath (lpPath, m_szServerName);
|
|
|
|
if (!lpFullPath)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetFullPath: Failed to build new DS object path")));
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Get the GPO DC for this domain
|
|
//
|
|
|
|
lpGPDCName = GetDCName (lpDomainName, NULL, hParent, TRUE, 0);
|
|
|
|
if (!lpGPDCName)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetFullPath: Failed to get DC name for %s"),
|
|
lpDomainName));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Make the full path
|
|
//
|
|
|
|
lpFullPath = MakeFullPath (lpPath, lpGPDCName);
|
|
|
|
LocalFree (lpGPDCName);
|
|
|
|
if (!lpFullPath)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("CBrowserPP::GetFullPath: Failed to build new DS object path")));
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
if (lpDomainName)
|
|
{
|
|
LocalFree (lpDomainName);
|
|
}
|
|
|
|
return lpFullPath;
|
|
}
|