//+---------------------------------------------------------------------------- // // Windows NT Directory Service Property Pages // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: notify.cxx // // Contents: Change notification ref-counting object. // // Classes: CNotifyObj // // History: 20-Jan-98 EricB // //----------------------------------------------------------------------------- #include "pch.h" #include "proppage.h" #include "objlist.h" // g_ClassIconCache #define NOTIFYOUT(x) dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) " #x "\n", this)); #define DSPROP_WAITTIME 600000 // wait 600 seconds, 10 minutes. //+---------------------------------------------------------------------------- // // Function: ADsPropCreateNotifyObj // // Synopsis: Checks to see if the notification window/object exists for this // sheet instance and if not creates it. // // Arguments: [pAppThdDataObj] - the unmarshalled data object pointer. // [pwzADsObjName] - object path name. // [phNotifyObj] - to return the notificion window handle. // // Returns: HRESULTs. // //----------------------------------------------------------------------------- STDAPI ADsPropCreateNotifyObj(LPDATAOBJECT pAppThdDataObj, PWSTR pwzADsObjName, HWND * phNotifyObj) { return CNotifyObj::Create(pAppThdDataObj, pwzADsObjName, phNotifyObj); } //+---------------------------------------------------------------------------- // // Function: ADsPropGetInitInfo // // Synopsis: Pages call this at their init time to retreive DS object info. // // Arguments: [hNotifyObj] - the notificion window handle. // [pInitParams] - struct filled in with DS object info. // // Returns: FALSE if the notify window has gone away for some reason. // // Note that pInitParams->pWritableAttrs can be NULL if there are no writable // attributes. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropGetInitInfo(HWND hNotifyObj, PADSPROPINITPARAMS pInitParams) { return CNotifyObj::GetInitInfo(hNotifyObj, pInitParams); } //+---------------------------------------------------------------------------- // // Function: ADsPropSetHwndWithTitle // // Synopsis: Pages call this at their dialog init time to send their hwnd // to the Notify object. Use this function instead of // ADsPropSetHwnd for multi-select property pages. // // Arguments: [hNotifyObj] - the notificion window handle. // [hPage] - the page's window handle. // [ptzTitle] - the page's title // // Returns: FALSE if the notify window has gone away for some reason. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropSetHwndWithTitle(HWND hNotifyObj, HWND hPage, PTSTR ptzTitle) { return CNotifyObj::SetHwnd(hNotifyObj, hPage, ptzTitle); } //+---------------------------------------------------------------------------- // // Function: ADsPropSetHwnd // // Synopsis: Pages call this at their dialog init time to send their hwnd // to the Notify object. // // Arguments: [hNotifyObj] - the notificion window handle. // [hPage] - the page's window handle. // // Returns: FALSE if the notify window has gone away for some reason. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropSetHwnd(HWND hNotifyObj, HWND hPage) { return ADsPropSetHwndWithTitle(hNotifyObj, hPage, 0); } //+---------------------------------------------------------------------------- // // function: ADsPropCheckIfWritable // // Synopsis: See if the attribute is writable by checking if it is in // the allowedAttributesEffective array. // // Arguments: [pwzAttr] - the attribute name. // [pWritableAttrs] - the array of writable attributes. // // Returns: FALSE if the attribute name is not found in the writable-attrs // array or if the array pointer is NULL. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropCheckIfWritable(const PWSTR pwzAttr, const PADS_ATTR_INFO pWritableAttrs) { BOOL fWritable = FALSE; if (!pWritableAttrs || IsBadReadPtr(pWritableAttrs, sizeof(ADS_ATTR_INFO))) { return FALSE; } for (DWORD i = 0; i < pWritableAttrs->dwNumValues; i++) { if (_wcsicmp(pWritableAttrs->pADsValues[i].CaseIgnoreString, pwzAttr) == 0) { fWritable = TRUE; break; } } return fWritable; } //+---------------------------------------------------------------------------- // // function: ADsPropSendErrorMessage // // Synopsis: Adds an error message to a list which is presented when // ADsPropShowErrorDialog is called // // Arguments: [hNotifyObj] - the notificion window handle. // [pError] - the error structure // // Returns: FALSE if the notify window has gone away for some reason. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropSendErrorMessage(HWND hNotifyObj, PADSPROPERROR pError) { return SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_ERROR, 0, (LPARAM)pError) != 0; } //+---------------------------------------------------------------------------- // // function: ADsPropShowErrorDialog // // Synopsis: Presents an error dialog with the error messages accumulated // through calls to ADsPropSendErrorMessage // // Arguments: [hNotifyObj] - the notificion window handle. // [hPage] - the property page window handle. // // Returns: FALSE if the notify window has gone away for some reason. // //----------------------------------------------------------------------------- STDAPI_(BOOL) ADsPropShowErrorDialog(HWND hNotifyObj, HWND hPage) { #ifdef DSADMIN CNotifyObj* pNotifyObj = NULL; dspAssert(hNotifyObj); if (!IsWindow(hNotifyObj)) { return FALSE; } LRESULT lResult = SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ, 0, (LPARAM)&pNotifyObj); if (lResult && pNotifyObj) { CMultiSelectErrorDialog dlg(hNotifyObj, hPage); CPageInfo* pPageInfoArray = pNotifyObj->m_pPageInfoArray; UINT cPages = pNotifyObj->m_cPages; IDataObject* pDataObject = pNotifyObj->m_pAppThdDataObj; dspAssert(pPageInfoArray); dspAssert(cPages > 0); dspAssert(pDataObject); HRESULT hr = dlg.Init(pPageInfoArray, cPages, pDataObject); if (SUCCEEDED(hr)) { dlg.DoModal(); SetForegroundWindow(dlg.m_hWnd); for (UINT pageIdx = 0; pageIdx < cPages; pageIdx++) { pPageInfoArray[pageIdx].m_ApplyErrors.Clear(); pPageInfoArray[pageIdx].m_ApplyStatus = CPageInfo::notAttempted; } } } #endif return TRUE; } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::Create // // Synopsis: Creation procedure: creates instances of the object. // // Arguments: [pAppThdDataObj] - the unmarshalled data object pointer. // [pwzADsObjName] - object path name. // [phNotifyObj] - to return the notificion window handle. // // Returns: HRESULTs. // //----------------------------------------------------------------------------- HRESULT CNotifyObj::Create(LPDATAOBJECT pAppThdDataObj, PWSTR pwzADsObjName, HWND * phNotifyObj) { HWND hNotify; HRESULT hr = S_OK; // Only one caller at a time. // CNotifyCreateCriticalSection NotifyCS; // // See if the object/window already exist for this property sheet and // get the object DN. // hNotify = FindSheetNoSetFocus(pwzADsObjName); if (hNotify != NULL) { // The window already exists, return the window handle. // *phNotifyObj = hNotify; dspDebugOut((DEB_ITRACE, "CNotifyObj::Create returning existing notify obj HWND.\n")); return S_OK; } dspDebugOut((DEB_ITRACE, "CNotifyObj::Create, creating notify obj.\n")); long lNotifyHandle; PPROPSHEETCFG pSheetCfg; PROPSHEETCFG sheetCfg; ZeroMemory(&sheetCfg, sizeof(PROPSHEETCFG)); STGMEDIUM sm = {TYMED_NULL, NULL, NULL}; FORMATETC fmte = {g_cfDsPropCfg, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; hr = pAppThdDataObj->GetData(&fmte, &sm); if (FAILED(hr)) { if (hr != DV_E_FORMATETC) { REPORT_ERROR_FORMAT(hr, IDS_NOTIFYFAILURE, GetDesktopWindow()); return hr; } lNotifyHandle = 0; } else { pSheetCfg = (PPROPSHEETCFG)sm.hGlobal; dspAssert(pSheetCfg); memcpy(&sheetCfg, pSheetCfg, sizeof(PROPSHEETCFG)); GlobalFree(sm.hGlobal); } // // Create the notification object. // CNotifyObj * pNotifyObj = new CNotifyObj(pAppThdDataObj, &sheetCfg); CHECK_NULL_REPORT(pNotifyObj, GetDesktopWindow(), return ERROR_OUTOFMEMORY); if (pNotifyObj->m_hr != S_OK) { REPORT_ERROR_FORMAT(pNotifyObj->m_hr, IDS_NOTIFYFAILURE, GetDesktopWindow()); return pNotifyObj->m_hr; } dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) object allocated, pAppThdDataObj = 0x%08p\n", pNotifyObj, pAppThdDataObj)); if (!AllocWStr(pwzADsObjName, &pNotifyObj->m_pwzObjDN)) { return E_OUTOFMEMORY; } uintptr_t hThread; hThread = _beginthread(NotifyThreadFcn, 0, (PVOID)pNotifyObj); if (hThread == -1) { dspDebugOut((DEB_ERROR, "_beginthread failed with error %s\n", strerror(errno))); REPORT_ERROR_FORMAT(ERROR_NOT_ENOUGH_MEMORY, IDS_NOTIFYFAILURE, GetDesktopWindow()); return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } // // Wait for initialization to complete and return the results. // if (WaitForSingleObject(pNotifyObj->m_hInitEvent, DSPROP_WAITTIME) == WAIT_TIMEOUT) { CloseHandle(pNotifyObj->m_hInitEvent); REPORT_ERROR_FORMAT(0, IDS_NOTIFYTIMEOUT, GetDesktopWindow()); return HRESULT_FROM_WIN32(WAIT_TIMEOUT); } CloseHandle(pNotifyObj->m_hInitEvent); if (pNotifyObj->m_hWnd != NULL) { *phNotifyObj = pNotifyObj->m_hWnd; } else { REPORT_ERROR_FORMAT(pNotifyObj->m_hr, IDS_NOTIFYFAILURE, GetDesktopWindow()); hr = pNotifyObj->m_hr; delete pNotifyObj; return hr; } return S_OK; } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::GetInitInfo // // Synopsis: Pages call this at their init time to retreive DS object info. // // Arguments: [hNotifyObj] - the notificion window handle. // [pInitParams] - struct filled in with DS object info. // // Note that pInitParams->pWritableAttrs can be NULL if there are no writable // attributes. // //----------------------------------------------------------------------------- BOOL CNotifyObj::GetInitInfo(HWND hNotifyObj, PADSPROPINITPARAMS pInitParams) { dspDebugOut((DEB_ITRACE, "CNotifyObj::GetInitInfo\n")); if (IsBadWritePtr(pInitParams, sizeof(ADSPROPINITPARAMS))) { return FALSE; } dspAssert(hNotifyObj && pInitParams); if (!IsWindow(hNotifyObj)) { pInitParams->hr = E_FAIL; return FALSE; } if (pInitParams->dwSize != sizeof (ADSPROPINITPARAMS)) { return FALSE; } SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_PAGEINIT, 0, (LPARAM)pInitParams); return TRUE; } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::SetHwnd // // Synopsis: Pages call this at their dialog init time to send their hwnd. // // Arguments: [hNotifyObj] - the notificion window handle. // [hPage] - the page's window handle. // // Returns: FALSE if the notify window has gone away for some reason. // //----------------------------------------------------------------------------- BOOL CNotifyObj::SetHwnd(HWND hNotifyObj, HWND hPage, PTSTR ptzTitle) { dspDebugOut((DEB_ITRACE, "CNotifyObj::SetHwnd\n")); dspAssert(hNotifyObj && hPage); if (!IsWindow(hNotifyObj)) { return FALSE; } SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_PAGEHWND, (WPARAM)hPage, (LPARAM)ptzTitle); return TRUE; } //+---------------------------------------------------------------------------- // // Method: NotifyThreadFcn // // Synopsis: Object window creation and message loop thread. // //----------------------------------------------------------------------------- VOID __cdecl NotifyThreadFcn(PVOID pParam) { // All of the function except the _endthread() call is enclosed in braces // so that the dtors of the auto classes would run. Otherwise the thread is // ended before the function scope is left and the auto class object dtors // never run. { CNotifyObj * pNotifyObj = (CNotifyObj *)pParam; dspAssert(pNotifyObj); MSG msg; CSmartPtr ptzTitle; if (!UnicodeToTchar(pNotifyObj->m_pwzObjDN, &ptzTitle)) { pNotifyObj->m_hr = E_OUTOFMEMORY; SetEvent(pNotifyObj->m_hInitEvent); return; } CStr cstrTitle(ptzTitle); WCHAR szIH[10]; _itow(g_iInstance, szIH, 16); cstrTitle += szIH; // // The window title is set to the DN of the object plus the instance // identifier converted to a string. This enables FindWindow to locate a // pre-existing instance of the notify window for a specific object for // a specific instance of DS Admin. // pNotifyObj->m_hWnd = CreateWindow(tzNotifyWndClass, cstrTitle, WS_POPUP, 0, 0, 1, 1, NULL, NULL, g_hInstance, pNotifyObj); if (pNotifyObj->m_hWnd == NULL) { DWORD dwErr = GetLastError(); dspDebugOut((DEB_ERROR, "Notify Obj window creation failed with error %d!\n", dwErr)); pNotifyObj->m_hr = HRESULT_FROM_WIN32(dwErr); SetEvent(pNotifyObj->m_hInitEvent); return; } dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) window creation complete.\n", pNotifyObj)); SetEvent(pNotifyObj->m_hInitEvent); while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } delete pNotifyObj; } _endthread(); } //+---------------------------------------------------------------------------- // // Method: _FindDSAHiddenWindowFromDSFind // // Synopsis: Looks for hidden DSA window of the snapin instance calling DS Find // // Returns: HWND of DSA hidden window if called from DS Find. // //----------------------------------------------------------------------------- BOOL CALLBACK EnumDSAHiddenWindowProc(HWND hwnd, LPARAM lParam) { HWND* phWnd = (HWND*)lParam; *phWnd = NULL; // get the window class TCHAR szClass[64]; if (0 == GetClassName(hwnd, szClass, 64)) { return TRUE; } if (_tcscmp(szClass, TEXT("DSAHiddenWindow")) != 0) { return TRUE; // no match, continue } // got a DSA hidden window // get the window title, to make sure it is // the one originating DS Find TCHAR szTitle[256]; ::GetWindowText(hwnd, szTitle, 256); if (_tcscmp(szTitle, TEXT("DS Find")) != 0) { return TRUE; // no match continue } // we go the right class and title, but // we still have to verify it is from the // same process (assuming DS Find modal) DWORD dwProcessId = 0x0; GetWindowThreadProcessId(hwnd, &dwProcessId); if (GetCurrentProcessId() != dwProcessId) { return TRUE; // from wrong process, continue } // finally, we got it!! *phWnd = hwnd; return FALSE; } HWND _FindDSAHiddenWindowFromDSFind() { HWND hwndHidden = NULL; EnumWindows(EnumDSAHiddenWindowProc, (LPARAM)&hwndHidden); return hwndHidden; } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::CNotifyObj // //----------------------------------------------------------------------------- CNotifyObj::CNotifyObj(LPDATAOBJECT pDataObj, PPROPSHEETCFG pSheetCfg) : m_hWnd(NULL), m_hPropSheet(NULL), m_cPages(0), m_cApplies(0), m_pAppThdDataObj(pDataObj), m_pStrmMarshalledDO(NULL), m_hInitEvent(NULL), m_fBeingDestroyed(FALSE), m_fSheetDirty(FALSE), m_hr(S_OK), m_pwzObjDN(NULL), m_pDsObj(NULL), m_pwzCN(NULL), m_pWritableAttrs(NULL), m_pAttrs(NULL), m_pPageInfoArray(NULL) { #ifdef _DEBUG strcpy(szClass, "CNotifyObj"); #endif memcpy(&m_sheetCfg, pSheetCfg, sizeof(PROPSHEETCFG)); if (m_sheetCfg.hwndHidden == NULL) { // we might be called from DS Find, so we want to find // the DSA hidden window, needed for creating // secondary property sheets m_sheetCfg.hwndHidden = _FindDSAHiddenWindowFromDSFind(); } // // We need to addref the data object but can't release it on this thread, // so we marshall it (which implicitly addrefs it) and then then unmarshall // and release on the notify object thread. // CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObj, &m_pStrmMarshalledDO); m_hInitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hInitEvent == NULL) { m_hr = HRESULT_FROM_WIN32(GetLastError()); } // // Arbitrary default size. This will expand as more pages are added // m_nPageInfoArraySize = 5; m_pPageInfoArray = new CPageInfo[m_nPageInfoArraySize]; } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::~CNotifyObj // //----------------------------------------------------------------------------- CNotifyObj::~CNotifyObj(void) { NOTIFYOUT(destructor); LPDATAOBJECT pNotifyThdDataObj = NULL; if (m_pStrmMarshalledDO) { CoGetInterfaceAndReleaseStream(m_pStrmMarshalledDO, IID_IDataObject, reinterpret_cast(&pNotifyThdDataObj)); m_pStrmMarshalledDO = NULL; } DO_RELEASE(pNotifyThdDataObj); //DBG_OUT("-----------------------releasing object in notify obj dtor"); DO_RELEASE(m_pDsObj); if (m_sheetCfg.lNotifyHandle) { MMCFreeNotifyHandle(m_sheetCfg.lNotifyHandle); } if (m_sheetCfg.hwndHidden && m_sheetCfg.wParamSheetClose) { ::PostMessage(m_sheetCfg.hwndHidden, WM_DSA_SHEET_CLOSE_NOTIFY, (WPARAM)m_sheetCfg.wParamSheetClose, (LPARAM)0); } DO_DEL(m_pwzObjDN); if (m_pAttrs) { FreeADsMem(m_pAttrs); } if (m_pPageInfoArray != NULL) { delete[] m_pPageInfoArray; m_pPageInfoArray = NULL; } } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::StaticNotifyProc // // Synopsis: window procedure // //----------------------------------------------------------------------------- LRESULT CALLBACK CNotifyObj::StaticNotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CNotifyObj * pNotifyObj = (CNotifyObj*)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (uMsg == WM_CREATE) { pNotifyObj = (CNotifyObj *)((CREATESTRUCT *)lParam)->lpCreateParams; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pNotifyObj); } if (pNotifyObj) { return pNotifyObj->NotifyProc(hWnd, uMsg, wParam, lParam); } return DefWindowProc(hWnd, uMsg, wParam, lParam); } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::NotifyProc // // Synopsis: Instance window procedure // //----------------------------------------------------------------------------- LRESULT CALLBACK CNotifyObj::NotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: return OnCreate(); case WM_ADSPROP_NOTIFY_PAGEINIT: dspDebugOut((DEB_ITRACE, "Notify Obj 0x%p: WM_ADSPROP_NOTIFY_PAGEINIT\n", this)); PADSPROPINITPARAMS pInitParams; pInitParams = (PADSPROPINITPARAMS)lParam; pInitParams->hr = m_hr; pInitParams->pDsObj = m_pDsObj; pInitParams->pwzCN = m_pwzCN; pInitParams->pWritableAttrs = m_pWritableAttrs; return 0; case WM_ADSPROP_NOTIFY_PAGEHWND: { m_cApplies = ++m_cPages; dspDebugOut((DEB_ITRACE, "Notify Obj 0x%p: WM_ADSPROP_NOTIFY_PAGEHWND count now %d\n", this, m_cPages)); HWND hWndPage = (HWND)wParam; if (!m_hPropSheet) { m_hPropSheet = GetParent(hWndPage); } if (m_cPages > m_nPageInfoArraySize) { // // REVIEW_JEFFJON : after going beyond the initial size, should the size increase // incrementally or in chunks? // CPageInfo* pNewPageInfoArray = new CPageInfo[m_cPages]; if (pNewPageInfoArray != NULL) { memset(pNewPageInfoArray, 0, sizeof(CPageInfo) * m_cPages); memcpy(pNewPageInfoArray, m_pPageInfoArray, sizeof(CPageInfo) * m_nPageInfoArraySize); delete[] m_pPageInfoArray; m_pPageInfoArray = pNewPageInfoArray; m_nPageInfoArraySize = m_cPages; } } m_pPageInfoArray[m_cPages - 1].m_hWnd = hWndPage; // // Copy the title if one was sent // PTSTR ptzPageTitle = reinterpret_cast(lParam); if (ptzPageTitle != NULL) { size_t iTitleSize = _tcslen(ptzPageTitle); m_pPageInfoArray[m_cPages - 1].m_ptzTitle = new TCHAR[iTitleSize + 1]; if (m_pPageInfoArray[m_cPages - 1].m_ptzTitle != NULL) { _tcscpy(m_pPageInfoArray[m_cPages - 1].m_ptzTitle, ptzPageTitle); } } } return 0; case WM_ADSPROP_NOTIFY_APPLY: { NOTIFYOUT(WM_ADSPROP_NOTIFY_APPLY); if ((BOOL)wParam) { // The security page and extension pages don't inherit from our // page framework and thus don't participate in the notify object // refcounting or the page-dirty flagging. So, don't fire a change // notification unless one of our pages was dirty. // m_fSheetDirty = TRUE; } // NTRAID#NTBUG9-462165-2001/10/17-JeffJon // Need to set the apply status to success. HWND hPage = reinterpret_cast(lParam); if (hPage) { for (UINT idx = 0; idx < m_cPages; idx++) { if (m_pPageInfoArray[idx].m_hWnd == hPage) { m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::success; break; } } } if (--m_cApplies == 0 && m_fSheetDirty) { NOTIFYOUT(Sending change notification); if (m_sheetCfg.lNotifyHandle) { // The change notify call results in a PostMessage back to the // MMC main thread. Therefore, we need to pass the data object // pointer that came from the main thread. // MMCPropertyChangeNotify(m_sheetCfg.lNotifyHandle, (LPARAM)m_pAppThdDataObj); } if (m_sheetCfg.hwndParentSheet) { PostMessage(m_sheetCfg.hwndParentSheet, WM_ADSPROP_NOTIFY_CHANGE, 0, 0); } m_cApplies = m_cPages; m_fSheetDirty = FALSE; // // Change the status of all the pages back to notAttempted // for (UINT idx = 0; idx < m_cPages; idx++) { m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::notAttempted; } } return 0; } case WM_ADSPROP_NOTIFY_ERROR: { NOTIFYOUT(WM_ADSPROP_NOTIFY_ERROR); PADSPROPERROR pApplyErrors = reinterpret_cast(lParam); if (pApplyErrors != NULL) { for (UINT idx = 0; idx < m_cPages; idx++) { if (m_pPageInfoArray[idx].m_hWnd == pApplyErrors->hwndPage) { m_pPageInfoArray[idx].m_ApplyErrors.SetError(pApplyErrors); if (m_pPageInfoArray[idx].m_ApplyErrors.GetErrorCount() > 0) { m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::failed; } else { m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::success; } break; } } } return 0; } case WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ: { NOTIFYOUT(WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ); BOOL retVal = FALSE; if (lParam != NULL) { CNotifyObj** ppNotifyObj = reinterpret_cast(lParam); if (ppNotifyObj) { *ppNotifyObj = this; retVal = TRUE; } } return retVal; } case WM_ADSPROP_NOTIFY_SETFOCUS: NOTIFYOUT(WM_ADSPROP_NOTIFY_SETFOCUS); SetForegroundWindow(m_hPropSheet); return 0; case WM_ADSPROP_NOTIFY_FOREGROUND: NOTIFYOUT(WM_ADSPROP_NOTIFY_FOREGROUND); if (wParam) // bActivate flag { SetForegroundWindow(m_hPropSheet); } else { SetWindowPos(m_hPropSheet, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); } return 0; case WM_ADSPROP_SHEET_CREATE: NOTIFYOUT(WM_ADSPROP_SHEET_CREATE); if (m_sheetCfg.hwndHidden) { ::PostMessage(m_sheetCfg.hwndHidden, WM_DSA_SHEET_CREATE_NOTIFY, wParam, lParam); } return 0; case WM_ADSPROP_NOTIFY_EXIT: { NOTIFYOUT(WM_ADSPROP_NOTIFY_EXIT); if (m_fBeingDestroyed) { return 0; } m_fBeingDestroyed = TRUE; DestroyWindow(hWnd); return 0; } case WM_DESTROY: NOTIFYOUT(WM_DESTROY); CoUninitialize(); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } //+---------------------------------------------------------------------------- // // Method: CNotifyObj::OnCreate // // Synopsis: Window creation/initialization processing. Bind to the DS // object and read its CN and Allowed-Attributes-Effective // properties. // //----------------------------------------------------------------------------- LRESULT CNotifyObj::OnCreate(void) { NOTIFYOUT(WM_CREATE); HRESULT hr; DWORD cAttrs; CoInitialize(NULL); // // we need to check to see if we can // convert the string to a CLSID. If // we can then this is a multi-select // property page and we shouldn't try // to bind. // CLSID clsid; if (SUCCEEDED(::CLSIDFromString(m_pwzObjDN, &clsid))) { m_hr = S_OK; return S_OK; } //DBG_OUT("+++++++++++++++++++++++++++addrefing (opening) object"); hr = ADsOpenObject(m_pwzObjDN, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (PVOID *)&m_pDsObj); if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { // ErrMsg(IDS_ERRMSG_NO_LONGER_EXISTS); m_hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } if (hr == 0x80070051) { // On subsequent network failures, ADSI returns this error code which // is not documented anywhere. I'll turn it into a documented error // code which happens to be the code returned on the first failure. // hr = HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP); } if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP)) { // ErrMsg(IDS_ERRMSG_NO_DC_RESPONSE); m_hr = HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP); return 0; } CHECK_HRESULT(hr, m_hr = hr; return hr); PWSTR rgszNames[2] = {g_wzName, g_wzAllowed}; hr = m_pDsObj->GetObjectAttributes(rgszNames, 2, &m_pAttrs, &cAttrs); CHECK_HRESULT(hr, m_hr = hr; return hr); dspAssert(cAttrs >= 1); // expect to always get name. for (DWORD i = 0; i < cAttrs; i++) { if (_wcsicmp(m_pAttrs[i].pszAttrName, g_wzName) == 0) { m_pwzCN = m_pAttrs[i].pADsValues->CaseIgnoreString; continue; } if (_wcsicmp(m_pAttrs[i].pszAttrName, g_wzAllowed) == 0) { m_pWritableAttrs = &m_pAttrs[i]; #if DBG == 1 for (DWORD j = 0; j < m_pAttrs[i].dwNumValues; j++) { dspDebugOut((DEB_USER4, "Allowed attribute (effective): %ws\n", m_pAttrs[i].pADsValues[j].CaseIgnoreString)); } #endif } } NOTIFYOUT(WM_CREATE done); return 0; } //+---------------------------------------------------------------------------- // // Function: RegisterNotifyClass // // Synopsis: Register the window class for the notification window. // //----------------------------------------------------------------------------- VOID RegisterNotifyClass(void) { WNDCLASS wcls; wcls.style = 0; wcls.lpfnWndProc = CNotifyObj::StaticNotifyProc; wcls.cbClsExtra = 0; wcls.cbWndExtra = 0; wcls.hInstance = g_hInstance; wcls.hIcon = NULL; wcls.hCursor = NULL; wcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wcls.lpszMenuName = NULL; wcls.lpszClassName = tzNotifyWndClass; RegisterClass(&wcls); } //+---------------------------------------------------------------------------- // // Function: FindSheetNoSetFocus // // Synopsis: Locate the property sheet for the DS object. // //----------------------------------------------------------------------------- HWND FindSheetNoSetFocus(PWSTR pwzObjADsPath) { HWND hNotify = NULL; // // See if the object/window already exists for this property sheet. // Note that the window title is the DN of the object plus the instance id. // #ifdef UNICODE CStr cstrTitle(pwzObjADsPath); WCHAR szIH[10]; _itow(g_iInstance, szIH, 16); cstrTitle += szIH; hNotify = FindWindow(tzNotifyWndClass, cstrTitle); #else LPSTR pszTitle; if (UnicodeToTchar(pwzObjADsPath, &pszTitle)) { CStr cstrTitle(pszTitle); char szIH[10]; _itoa(g_iInstance, szIH, 16); cstrTitle += szIH; hNotify = FindWindow(tzNotifyWndClass, cstrTitle); delete [] pszTitle; } #endif dspDebugOut((DEB_ITRACE, "FindSheet: returned hNotify = 0x%08x\n", hNotify)); return hNotify; } //+---------------------------------------------------------------------------- // // Function: BringSheetToForeground // // Synopsis: Locate the property sheet for the DS object identified by the // data object and bring it to the top of the Z order // //----------------------------------------------------------------------------- extern "C" BOOL BringSheetToForeground(PWSTR pwzObjADsPath, BOOL bActivate) { HWND hNotify = FindSheetNoSetFocus(pwzObjADsPath); if (!hNotify) { return FALSE; } PostMessage(hNotify, WM_ADSPROP_NOTIFY_FOREGROUND, (WPARAM)bActivate, 0); return TRUE; } //+---------------------------------------------------------------------------- // // Function: FindSheet // // Synopsis: Locate the property sheet for the DS object identified by the // data object. For use in the dsprop DLL. If found, bring the // sheet to the foregroung and set the focus to the sheet. // //----------------------------------------------------------------------------- BOOL FindSheet(PWSTR pwzObjADsPath) { HWND hNotify = FindSheetNoSetFocus(pwzObjADsPath); if (!hNotify) { return FALSE; } SendMessage(hNotify, WM_ADSPROP_NOTIFY_SETFOCUS, 0, 0); return TRUE; } //+---------------------------------------------------------------------------- // // Function: IsSheetAlreadyUp // // Synopsis: Public, exported function to locate a prop sheet for the DS // object identified by the data object. If found, sends a message // to the sheet to bring it to the foreground. // //----------------------------------------------------------------------------- extern "C" BOOL IsSheetAlreadyUp(LPDATAOBJECT pDataObj) { // Get the object's DN from the data object. // HRESULT hr = S_OK; STGMEDIUM sm = {TYMED_NULL, NULL, NULL}; FORMATETC fmte = {g_cfDsMultiSelectProppages, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; PWSTR pszUniqueID; BOOL fFound = FALSE; hr = pDataObj->GetData(&fmte, &sm); if (FAILED(hr)) { STGMEDIUM smDS = {TYMED_NULL, NULL, NULL}; FORMATETC fmteDS = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; LPDSOBJECTNAMES pDsObjectNames; hr = pDataObj->GetData(&fmteDS, &smDS); if (FAILED(hr)) { return FALSE; } pDsObjectNames = (LPDSOBJECTNAMES)smDS.hGlobal; dspAssert(pDsObjectNames->cItems > 0); pszUniqueID = (LPWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName); fFound = FindSheet(pszUniqueID); GlobalFree(smDS.hGlobal); } else { pszUniqueID = (PWSTR)sm.hGlobal; dspAssert(pszUniqueID != NULL); fFound = FindSheet(pszUniqueID); ReleaseStgMedium(&sm); } return fFound; } #ifdef DSADMIN //+---------------------------------------------------------------------------- // // Method: CMultiSelectErrorDialog::CMultiSelectErrorDialog // // Synopsis: Multi-select error message dialog constructor // //----------------------------------------------------------------------------- CMultiSelectErrorDialog::CMultiSelectErrorDialog(HWND hNotifyObj, HWND hParent) : m_hWnd(NULL), m_hNotifyObj(hNotifyObj), m_hParent(hParent), m_bModal(FALSE), m_bInit(FALSE), m_pPageInfoArray(NULL), m_nPageCount(0), m_pDataObj(NULL) { } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::StaticDlgProc // // Synopsis: The static dialog proc for displaying errors for multi-select pages // //----------------------------------------------------------------------------- LRESULT CALLBACK CMultiSelectErrorDialog::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMultiSelectErrorDialog* dlg = NULL; UINT code; UINT id; switch (uMsg) { case WM_INITDIALOG: dlg = reinterpret_cast(lParam); dspAssert(dlg != NULL); SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)dlg); SetForegroundWindow(hDlg); return dlg->OnInitDialog(hDlg); case WM_COMMAND: code = GET_WM_COMMAND_CMD(wParam, lParam); id = GET_WM_COMMAND_ID(wParam, lParam); if (dlg == NULL) { dlg = reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); } switch (id) { case IDOK: case IDCANCEL: if (code == BN_CLICKED) { dlg->OnClose(); } break; case IDC_COPY_BUTTON: if (code == BN_CLICKED) { dlg->OnCopyButton(); } break; case IDC_PROPERTIES_BUTTON: if (code == BN_CLICKED) { dlg->ShowListViewItemProperties(); } break; } break; case WM_NOTIFY: { if (dlg == NULL) { dlg = reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); } int idCtrl = (int)wParam; LPNMHDR pnmh = reinterpret_cast(lParam); if (idCtrl == IDC_ERROR_LIST) { switch (pnmh->code) { case NM_DBLCLK: { dlg->ListItemActivate(pnmh); } break; case LVN_ITEMCHANGED: case NM_CLICK: { dlg->ListItemClick(pnmh); } break; default: break; } } break; } case WM_HELP: { LPHELPINFO pHelpInfo = reinterpret_cast(lParam); if (!pHelpInfo || pHelpInfo->iCtrlId < 1 || IDH_NO_HELP == pHelpInfo->dwContextId) { return 0; } WinHelp(hDlg, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId); break; } } return 0; } BOOL LoadStringToTcharFromDsPrpRes(int ids, PTSTR * pptstr) { static const int MAX_STRING = 1024; TCHAR szBuf[MAX_STRING]; HMODULE hDsPropRes = ::LoadLibraryEx(L"dsprpres.dll", 0, LOAD_LIBRARY_AS_DATAFILE); BOOL result = FALSE; do { if (!LoadString(hDsPropRes, ids, szBuf, MAX_STRING - 1)) { break; } *pptstr = new TCHAR[_tcslen(szBuf) + 1]; CHECK_NULL(*pptstr, return FALSE); _tcscpy(*pptstr, szBuf); result = TRUE; } while (0); ::FreeLibrary(hDsPropRes); return result; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::Init // // Synopsis: Initializes the member variables // //----------------------------------------------------------------------------- BOOL CMultiSelectErrorDialog::OnInitDialog(HWND hDlg) { dspAssert(m_bInit); if (!m_bInit) { return TRUE; } m_hWnd = hDlg; // // Disable the properties button until there is a selection // EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), FALSE); HRESULT hr = S_OK; hr = InitializeListBox(hDlg); CHECK_HRESULT(hr, return TRUE;); CComPtr spPathCracker; hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); CHECK_HRESULT_REPORT(hr, hDlg, return TRUE); dspAssert(m_pPageInfoArray != NULL); if (m_pPageInfoArray == NULL) { return TRUE; } INT iMaxLen = 0; SIZE size = {0,0}; // // Load the appropriate list box // for (UINT pageIdx = 0; pageIdx < m_nPageCount; pageIdx++) { if (m_pPageInfoArray[pageIdx].m_ApplyStatus == CPageInfo::failed) { PTSTR ptzCaptionFormat = NULL; LoadStringToTcharFromDsPrpRes(IDS_MULTI_FAILURE_CAPTION, &ptzCaptionFormat); if (ptzCaptionFormat != NULL) { PWSTR pszCaption = new WCHAR[wcslen(ptzCaptionFormat) + wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetPageTitle()) + 1]; if (pszCaption != NULL) { wsprintf(pszCaption, ptzCaptionFormat, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetPageTitle()); SetWindowText(GetDlgItem(m_hWnd, IDC_ERROR_STATIC), pszCaption); delete[] pszCaption; pszCaption = NULL; } } for (UINT objectIdx = 0; objectIdx < m_pPageInfoArray[pageIdx].m_ApplyErrors.GetCount(); objectIdx++) { // // Get the objects path and class name // PWSTR pszObjPath = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetName(objectIdx); PWSTR pszObjClass = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetClass(objectIdx); // // Get the class icon for the object // int iIcon = g_ClassIconCache.GetClassIconIndex(pszObjClass); dspAssert(iIcon != -1); // // Get the object name from the path // PWSTR pszLabel = NULL; CComBSTR bstr; hr = spPathCracker->Set(pszObjPath, ADS_SETTYPE_FULL); CHECK_HRESULT(hr, pszLabel = pszObjPath;); if (SUCCEEDED(hr)) { hr = spPathCracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY); CHECK_HRESULT(hr, pszLabel = pszObjPath;); } // CODEWORK 122531 Should we be turning off escaped mode here? if (SUCCEEDED(hr)) { hr = spPathCracker->Retrieve(ADS_FORMAT_LEAF, &bstr); CHECK_HRESULT(hr, pszLabel = pszObjPath;); } if (SUCCEEDED(hr)) { pszLabel = bstr; } dspAssert(pszLabel != NULL); // // Create the list view item // LV_ITEM lvi = {0}; lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iSubItem = IDX_NAME_COL; lvi.lParam = (LPARAM)pszObjPath; lvi.pszText = pszLabel; lvi.iItem = objectIdx; if (-1 != iIcon) { lvi.mask |= LVIF_IMAGE; lvi.iImage = iIcon; } // // Insert the new item // int NewIndex = ListView_InsertItem(m_hList, &lvi); dspAssert(NewIndex != -1); if (NewIndex == -1) { continue; } // // Format the error message and insert it // PWSTR ptzMsg = NULL; if (FAILED(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx))) { LoadErrorMessage(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx), 0, &ptzMsg); if (!ptzMsg) { ptzMsg = L""; // make prefix happy. } // // REVIEW_JEFFJON : this is hack to get rid of two extra characters // at the end of the string // size_t iLen = wcslen(ptzMsg); ptzMsg[iLen - 2] = L'\0'; } else { ptzMsg = new WCHAR[wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)) + 1]; if (ptzMsg != NULL) { wcscpy(ptzMsg, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)); } } if (NULL != ptzMsg) { ListView_SetItemText(m_hList, NewIndex, IDX_ERROR_COL, ptzMsg); INT len = lstrlen(ptzMsg); if( len > iMaxLen ) { HDC hdc = GetDC(hDlg); GetTextExtentPoint32(hdc,ptzMsg,lstrlen(ptzMsg),&size); ReleaseDC(hDlg, hdc); iMaxLen = len; } delete[] ptzMsg; } } } else if (m_pPageInfoArray[pageIdx].m_ApplyStatus == CPageInfo::success) { // // Insert the page title into the success list box // SendDlgItemMessage(m_hWnd, IDC_SUCCESS_LISTBOX, LB_ADDSTRING, 0, (LPARAM)m_pPageInfoArray[pageIdx].m_ptzTitle); } else // apply not tried yet { // // Insert the page title into the not attempted list box // SendDlgItemMessage(m_hWnd, IDC_NOT_ATTEMPTED_LISTBOX, LB_ADDSTRING, 0, (LPARAM)m_pPageInfoArray[pageIdx].m_ptzTitle); } } // // Select the first item in the error list // LVCOLUMN col; col.mask = LVCF_WIDTH; col.cx = size.cx; ListView_SetColumn(m_hList,1, &col); ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT); ListView_SetItemState(m_hList, 0, LVIS_SELECTED, LVIS_SELECTED); return TRUE; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::InitializeListBox // // Synopsis: Initializes the member variables // //----------------------------------------------------------------------------- HRESULT CMultiSelectErrorDialog::InitializeListBox(HWND hDlg) { m_hList = GetDlgItem(hDlg, IDC_ERROR_LIST); if (m_hList == NULL) { return HRESULT_FROM_WIN32(GetLastError()); } ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT); // // Set the column headings. // PTSTR ptsz; RECT rect; GetClientRect(m_hList, &rect); if (!LoadStringToTchar(IDS_COL_TITLE_OBJNAME, &ptsz)) { ReportError(GetLastError(), 0, hDlg); return HRESULT_FROM_WIN32(GetLastError()); } LV_COLUMN lvc = {0}; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.cx = OBJ_LIST_NAME_COL_WIDTH; lvc.pszText = ptsz; lvc.iSubItem = IDX_NAME_COL; ListView_InsertColumn(m_hList, IDX_NAME_COL, &lvc); delete[] ptsz; if (!LoadStringToTchar(IDS_COL_TITLE_ERRORMSG, &ptsz)) { ReportError(GetLastError(), 0, hDlg); return HRESULT_FROM_WIN32(GetLastError()); } lvc.cx = rect.right - OBJ_LIST_NAME_COL_WIDTH; lvc.pszText = ptsz; lvc.iSubItem = IDX_ERROR_COL; ListView_InsertColumn(m_hList, IDX_ERROR_COL, &lvc); delete[] ptsz; // // Assign the imagelist to the listview // ListView_SetImageList(m_hList, g_ClassIconCache.GetImageList(), LVSIL_SMALL); return S_OK; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::Init // // Synopsis: Initializes the member variables // //----------------------------------------------------------------------------- HRESULT CMultiSelectErrorDialog::Init(CPageInfo* pPageInfoArray, UINT nPageCount, IDataObject* pDataObj) { m_nPageCount = nPageCount; m_pPageInfoArray = pPageInfoArray; m_bInit = TRUE; m_pDataObj = pDataObj; m_pDataObj->AddRef(); return S_OK; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::OnCopyButton // // Synopsis: Called when the user presses the Retry button // //----------------------------------------------------------------------------- void CMultiSelectErrorDialog::OnCopyButton() { dspAssert(m_bInit); if (!m_bInit) { return; } dspAssert(m_pPageInfoArray != NULL); if (m_pPageInfoArray == NULL) { return; } CComPtr spPathCracker; HRESULT hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); CHECK_HRESULT_REPORT(hr, m_hWnd, return); if (OpenClipboard(m_hWnd) == 0) { return; } if (EmptyClipboard() == 0) { CloseClipboard(); return; } CStrW szClipboardData; szClipboardData.Empty(); for (UINT pageIdx = 0; pageIdx < m_nPageCount; pageIdx++) { for (UINT objectIdx = 0; objectIdx < m_pPageInfoArray[pageIdx].m_ApplyErrors.GetCount(); objectIdx++) { // // Get the objects path and class name // PWSTR pszObjPath = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetName(objectIdx); // // Get the object name from the path // PWSTR pszLabel = NULL; CComBSTR bstr; hr = spPathCracker->Set(pszObjPath, ADS_SETTYPE_FULL); CHECK_HRESULT(hr, pszLabel = pszObjPath;); if (SUCCEEDED(hr)) { hr = spPathCracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY); CHECK_HRESULT(hr, pszLabel = pszObjPath;); } // CODEWORK 122531 Should we be turning off escaped mode here? if (SUCCEEDED(hr)) { hr = spPathCracker->Retrieve(ADS_FORMAT_LEAF, &bstr); CHECK_HRESULT(hr, pszLabel = pszObjPath;); } if (SUCCEEDED(hr)) { pszLabel = bstr; } dspAssert(pszLabel != NULL); // // Format the error message and insert it // PWSTR ptzMsg = NULL; if (FAILED(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx))) { LoadErrorMessage(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx), 0, &ptzMsg); } else { ptzMsg = new WCHAR[wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)) + 1]; if (ptzMsg != NULL) { wcscpy(ptzMsg, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)); } } if (NULL != ptzMsg) { szClipboardData += pszLabel; szClipboardData += L","; szClipboardData += ptzMsg; szClipboardData += g_wzCRLF; delete ptzMsg; } } } HGLOBAL hBuffer = NULL; DWORD dwBufferSize; HANDLE hMemClipboard; LPTSTR pszGlobalBuffer = NULL; dwBufferSize = (szClipboardData.GetLength() + 1) * sizeof(TCHAR); hBuffer = GlobalAlloc (GMEM_MOVEABLE, dwBufferSize); pszGlobalBuffer = (LPTSTR)GlobalLock (hBuffer); if ( NULL == pszGlobalBuffer ) { // allocation or lock failed so bail out GlobalFree (hBuffer); return; } _tcscpy ( pszGlobalBuffer, szClipboardData ); GlobalUnlock (hBuffer); if ( NULL != hBuffer ) { hMemClipboard = SetClipboardData ( #if UNICODE CF_UNICODETEXT, // UNICODE text in the clipboard #else CF_TEXT, // ANSI text in the clipboard #endif hBuffer); if (hMemClipboard == NULL) { //free memory since it didn't make it to the clipboard GlobalFree (hBuffer); return; } } else { //free memory since it didn't make it to the clipboard GlobalFree (hBuffer); return; } CloseClipboard(); } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::ListItemClick // // Synopsis: Invokes a property page for the item that was activated // //----------------------------------------------------------------------------- void CMultiSelectErrorDialog::ListItemClick(LPNMHDR) { UINT nSelectedCount = ListView_GetSelectedCount(m_hList); if (nSelectedCount == 1) { EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), TRUE); } else { EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), FALSE); } } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::ListItemActivate // // Synopsis: Invokes a property page for the item that was activated // //----------------------------------------------------------------------------- void CMultiSelectErrorDialog::ListItemActivate(LPNMHDR pnmh) { LPNMITEMACTIVATE pActivateHeader = reinterpret_cast(pnmh); dspAssert(pActivateHeader != NULL); if (pActivateHeader != NULL) { ShowListViewItemProperties(); } } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::ShowListViewItemProperties() // // Synopsis: Invokes a secondary sheet for the selected list view item // //----------------------------------------------------------------------------- BOOL CMultiSelectErrorDialog::ShowListViewItemProperties() { BOOL bSuccess = TRUE; UINT nSelectCount = ListView_GetSelectedCount(m_hList); if (nSelectCount == 1) { // // Get the selected item // int nSelectedItem = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED); if (nSelectedItem != -1) { // // Retrieve the item's path // LVITEM lvi = {0}; lvi.iItem = nSelectedItem; lvi.mask = LVIF_PARAM; if (ListView_GetItem(m_hList, &lvi)) { PWSTR pwzPath = reinterpret_cast(lvi.lParam); if (pwzPath != NULL) { // // Get the DN // CComPtr spPathCracker; HRESULT hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;); hr = spPathCracker->Set(pwzPath, ADS_SETTYPE_FULL); CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;); hr = spPathCracker->put_EscapedMode(ADS_ESCAPEDMODE_ON); dspAssert(SUCCEEDED(hr)); hr = spPathCracker->SetDisplayType(ADS_DISPLAY_FULL); CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;); CComBSTR bstrDN; hr = spPathCracker->Retrieve(ADS_FORMAT_X500_DN, &bstrDN); CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;); // // Invoke the page // hr = PostADsPropSheet(bstrDN, m_pDataObj, m_hParent, m_hNotifyObj, FALSE); if (FAILED(hr)) { bSuccess = FALSE; } } else { bSuccess = FALSE; } } else { bSuccess = FALSE; } } else { bSuccess = FALSE; } } return bSuccess; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::OnClose // // Synopsis: Closes the modal dialog // //----------------------------------------------------------------------------- void CMultiSelectErrorDialog::OnClose() { EndDialog(m_hWnd, 0); } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::DoModal // // Synopsis: Displays the modal dialog // //----------------------------------------------------------------------------- int CMultiSelectErrorDialog::DoModal() { m_bModal = TRUE; dspAssert(IsWindow(m_hParent)); HMODULE hDsPropRes = ::LoadLibraryEx(L"dsprpres.dll", 0, LOAD_LIBRARY_AS_DATAFILE); int result = (int)DialogBoxParam(hDsPropRes, MAKEINTRESOURCE(IDD_MULTISELECT_ERROR_DIALOG), m_hParent, (DLGPROC)StaticDlgProc, (LPARAM)this); ::FreeLibrary(hDsPropRes); return result; } //+---------------------------------------------------------------------------- // // Member: CMultiSelectErrorDialog::ShowWindow // // Synopsis: Displays the modeless dialog // //----------------------------------------------------------------------------- BOOL CMultiSelectErrorDialog::ShowWindow() { m_bModal = FALSE; HMODULE hDsPropRes = ::LoadLibraryEx(L"dsprpres.dll", 0, LOAD_LIBRARY_AS_DATAFILE); m_hWnd = CreateDialogParam(hDsPropRes, MAKEINTRESOURCE(IDD_MULTISELECT_ERROR_DIALOG), m_hParent, (DLGPROC)StaticDlgProc, (LPARAM)this); BOOL result = ::ShowWindow(m_hWnd, SW_SHOWNORMAL); ::FreeLibrary(hDsPropRes); return result; } #endif // DSADMIN