Source code of Windows XP (NT5)
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.

690 lines
15 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. helper.cpp
  7. Implementation of the following helper classes:
  8. CDlgHelper -- enable, check, getcheck of dialog items
  9. CStrArray -- manages an array of CString*
  10. It doesn't duplicate the string when add
  11. It deletes the pointers during destruction
  12. It imports and exports SAFEARRAY of BSTRs
  13. It has copy operatators
  14. CManagedPage -- provide a middle layer between CpropertyPage and
  15. real property page class to manage: readonly, set modify, and
  16. context help info.
  17. CHelpDialog -- implments context help
  18. And global functions:
  19. BOOL CheckADsError() -- check error code from ADSI
  20. void DecorateName() -- make new name to "CN=name" for LDAP
  21. FILE HISTORY:
  22. */
  23. #include "stdafx.h"
  24. #include <afxtempl.h>
  25. #include <winldap.h>
  26. #include <dsgetdc.h>
  27. #include <mmc.h>
  28. #include "helper.h"
  29. #include "resource.h"
  30. // helper function -- enable a dialog button
  31. void CDlgHelper::EnableDlgItem(CDialog* pDialog, int id, bool bEnable)
  32. {
  33. CWnd* pWnd = pDialog->GetDlgItem(id);
  34. ASSERT(pWnd);
  35. pWnd->EnableWindow(bEnable);
  36. }
  37. // helper function -- set check status of a dialog button
  38. void CDlgHelper::SetDlgItemCheck(CDialog* pDialog, int id, int nCheck)
  39. {
  40. CButton* pButton = (CButton*)pDialog->GetDlgItem(id);
  41. ASSERT(pButton);
  42. pButton->SetCheck(nCheck);
  43. }
  44. // helper function -- get check status of a dialog button
  45. int CDlgHelper::GetDlgItemCheck(CDialog* pDialog, int id)
  46. {
  47. CButton* pButton = (CButton*)(pDialog->GetDlgItem(id));
  48. ASSERT(pButton);
  49. return pButton->GetCheck();
  50. }
  51. CStrArray& CStrArray::operator = (const CStrArray& sarray)
  52. {
  53. int count = GetSize();
  54. CString* pString;
  55. // remove existing members
  56. while(count --)
  57. {
  58. pString = GetAt(0);
  59. RemoveAt(0);
  60. delete pString;
  61. }
  62. // copy new
  63. count = sarray.GetSize();
  64. for(int i = 0; i < count; i++)
  65. {
  66. pString = new CString(*sarray[i]);
  67. Add(pString);
  68. }
  69. return *this;
  70. }
  71. // convert an array of CString to SAFEARRAY
  72. CStrArray::operator SAFEARRAY*()
  73. {
  74. USES_CONVERSION;
  75. int count = GetSize();
  76. if(count == 0) return NULL;
  77. SAFEARRAYBOUND bound[1];
  78. SAFEARRAY* pSA = NULL;
  79. CString* pStr = NULL;
  80. long l[2];
  81. VARIANT v;
  82. VariantInit(&v);
  83. bound[0].cElements = count;
  84. bound[0].lLbound = 0;
  85. try{
  86. // creat empty right size array
  87. pSA = SafeArrayCreate(VT_VARIANT, 1, bound);
  88. if(NULL == pSA) return NULL;
  89. // put in each element
  90. for (long i = 0; i < count; i++)
  91. {
  92. pStr = GetAt(i);
  93. V_VT(&v) = VT_BSTR;
  94. V_BSTR(&v) = T2BSTR((LPTSTR)(LPCTSTR)(*pStr));
  95. l[0] = i;
  96. SafeArrayPutElement(pSA, l, &v);
  97. VariantClear(&v);
  98. }
  99. }
  100. catch(CMemoryException&)
  101. {
  102. SafeArrayDestroy(pSA);
  103. pSA = NULL;
  104. VariantClear(&v);
  105. throw;
  106. }
  107. return pSA;
  108. }
  109. //build a StrArray from another array
  110. CStrArray::CStrArray(const CStrArray& sarray)
  111. {
  112. int count = sarray.GetSize();
  113. CString* pString = NULL;
  114. for(int i = 0; i < count; i++)
  115. {
  116. try{
  117. pString = new CString(*sarray[i]);
  118. Add(pString);
  119. }
  120. catch(CMemoryException&)
  121. {
  122. delete pString;
  123. throw;
  124. }
  125. }
  126. }
  127. //build a StrArray from a safe array
  128. CStrArray::CStrArray(SAFEARRAY* pSA)
  129. {
  130. if(pSA) AppendSA(pSA);
  131. }
  132. //remove the elements from the array and delete them
  133. int CStrArray::DeleteAll()
  134. {
  135. int ret, count;
  136. CString* pStr;
  137. ret = count = GetSize();
  138. while(count--)
  139. {
  140. pStr = GetAt(0);
  141. RemoveAt(0);
  142. delete pStr;
  143. }
  144. return ret;
  145. }
  146. CString* CStrArray::AddByRID(UINT id)
  147. {
  148. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  149. CString* pStr = NULL;
  150. try
  151. {
  152. pStr = new CString();
  153. pStr->LoadString(id);
  154. Add(pStr);
  155. }
  156. catch(CMemoryException&)
  157. {
  158. delete pStr;
  159. pStr = NULL;
  160. }
  161. return pStr;
  162. }
  163. //build a StrArray from a safe array
  164. bool CStrArray::AppendSA(SAFEARRAY* pSA)
  165. {
  166. if(!pSA) return false;
  167. CString* pString = NULL;
  168. long lIter;
  169. long lBound, uBound;
  170. VARIANT v;
  171. bool bSuc = true; // ser return value to true;
  172. USES_CONVERSION;
  173. VariantInit(&v);
  174. try{
  175. SafeArrayGetLBound(pSA, 1, &lBound);
  176. SafeArrayGetUBound(pSA, 1, &uBound);
  177. for(lIter = lBound; lIter <= uBound; lIter++)
  178. {
  179. if(SUCCEEDED(SafeArrayGetElement(pSA, &lIter, &v)))
  180. {
  181. if(V_VT(&v) == VT_BSTR)
  182. {
  183. pString = new CString;
  184. (*pString) = (LPCTSTR)W2T(V_BSTR(&v));
  185. Add(pString);
  186. }
  187. }
  188. }
  189. }
  190. catch(CMemoryException&)
  191. {
  192. delete pString;
  193. VariantClear(&v);
  194. bSuc = false;
  195. throw;
  196. }
  197. return bSuc;
  198. }
  199. //build a StrArray from a safe array
  200. CStrArray::~CStrArray()
  201. {
  202. DeleteAll();
  203. }
  204. // return index if found, otherwise -1;
  205. int CStrArray::Find(const CString& Str) const
  206. {
  207. int count = GetSize();
  208. while(count--)
  209. {
  210. if(*GetAt(count) == Str) break;
  211. }
  212. return count;
  213. }
  214. //build a DWArray from another array
  215. CDWArray::CDWArray(const CDWArray& dwarray)
  216. {
  217. int count = dwarray.GetSize();
  218. for(int i = 0; i < count; i++)
  219. {
  220. try{
  221. Add(dwarray[i]);
  222. }
  223. catch(CMemoryException&)
  224. {
  225. throw;
  226. }
  227. }
  228. }
  229. // return index if found, otherwise -1;
  230. int CDWArray::Find(const DWORD dw) const
  231. {
  232. int count = GetSize();
  233. while(count--)
  234. {
  235. if(GetAt(count) == dw) break;
  236. }
  237. return count;
  238. }
  239. CDWArray& CDWArray::operator = (const CDWArray& dwarray)
  240. {
  241. int count;
  242. RemoveAll();
  243. // copy new
  244. count = dwarray.GetSize();
  245. for(int i = 0; i < count; i++)
  246. {
  247. Add(dwarray[i]);
  248. }
  249. return *this;
  250. }
  251. /////////////////////////////////////////////////////////////////////////////
  252. // CManagedPage property page
  253. IMPLEMENT_DYNCREATE(CManagedPage, CPropertyPage)
  254. BEGIN_MESSAGE_MAP(CManagedPage, CPropertyPage)
  255. //{{AFX_MSG_MAP(CManagedPage)
  256. ON_WM_HELPINFO()
  257. ON_WM_CONTEXTMENU()
  258. //}}AFX_MSG_MAP
  259. END_MESSAGE_MAP()
  260. void CManagedPage::OnContextMenu(CWnd* pWnd, CPoint point)
  261. {
  262. if (m_pHelpTable)
  263. ::WinHelp (pWnd->m_hWnd, AfxGetApp()->m_pszHelpFilePath,
  264. HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID)m_pHelpTable);
  265. }
  266. BOOL CManagedPage::OnHelpInfo(HELPINFO* pHelpInfo)
  267. {
  268. if (pHelpInfo->iContextType == HELPINFO_WINDOW && m_pHelpTable)
  269. {
  270. ::WinHelp ((HWND)pHelpInfo->hItemHandle,
  271. AfxGetApp()->m_pszHelpFilePath,
  272. HELP_WM_HELP,
  273. (DWORD_PTR)(LPVOID)m_pHelpTable);
  274. }
  275. return TRUE;
  276. }
  277. //---------------------------------------------------------------------------
  278. // This is our self deleting callback function. If you have more than a
  279. // a few property sheets, it might be a good idea to implement this in a
  280. // base class and derive your MFC property sheets from the base class
  281. //
  282. UINT CALLBACK CManagedPage::PropSheetPageProc
  283. (
  284. HWND hWnd, // [in] Window handle - always null
  285. UINT uMsg, // [in,out] Either the create or delete message
  286. LPPROPSHEETPAGE pPsp // [in,out] Pointer to the property sheet struct
  287. )
  288. {
  289. ASSERT( NULL != pPsp );
  290. // We need to recover a pointer to the current instance. We can't just use
  291. // "this" because we are in a static function
  292. CManagedPage* pMe = reinterpret_cast<CManagedPage*>(pPsp->lParam);
  293. ASSERT( NULL != pMe );
  294. switch( uMsg )
  295. {
  296. case PSPCB_CREATE:
  297. break;
  298. case PSPCB_RELEASE:
  299. // Since we are deleting ourselves, save a callback on the stack
  300. // so we can callback the base class
  301. LPFNPSPCALLBACK pfnOrig = pMe->m_pfnOriginalCallback;
  302. delete pMe;
  303. return 1; //(pfnOrig)(hWnd, uMsg, pPsp);
  304. }
  305. // Must call the base class callback function or none of the MFC
  306. // message map stuff will work
  307. return (pMe->m_pfnOriginalCallback)(hWnd, uMsg, pPsp);
  308. } // end PropSheetPageProc()
  309. /////////////////////////////////////////////////////////////////////////////
  310. // CHelpDialog
  311. IMPLEMENT_DYNCREATE(CHelpDialog, CDialog)
  312. BEGIN_MESSAGE_MAP(CHelpDialog, CDialog)
  313. //{{AFX_MSG_MAP(CHelpDialog)
  314. ON_WM_HELPINFO()
  315. ON_WM_CONTEXTMENU()
  316. //}}AFX_MSG_MAP
  317. END_MESSAGE_MAP()
  318. void CHelpDialog::OnContextMenu(CWnd* pWnd, CPoint point)
  319. {
  320. if (m_pHelpTable)
  321. ::WinHelp (pWnd->m_hWnd, AfxGetApp()->m_pszHelpFilePath,
  322. HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID)m_pHelpTable);
  323. }
  324. BOOL CHelpDialog::OnHelpInfo(HELPINFO* pHelpInfo)
  325. {
  326. if (pHelpInfo->iContextType == HELPINFO_WINDOW && m_pHelpTable)
  327. {
  328. ::WinHelp ((HWND)pHelpInfo->hItemHandle,
  329. AfxGetApp()->m_pszHelpFilePath,
  330. HELP_WM_HELP,
  331. (DWORD_PTR)(LPVOID)m_pHelpTable);
  332. }
  333. return TRUE;
  334. }
  335. //+----------------------------------------------------------------------------
  336. //
  337. // Function: CheckADsError
  338. //
  339. // Sysnopsis: Checks the result code from an ADSI call.
  340. //
  341. // Returns: TRUE if no error.
  342. //
  343. //-----------------------------------------------------------------------------
  344. BOOL CheckADsError(HRESULT hr, BOOL fIgnoreAttrNotFound, PSTR file,
  345. int line)
  346. {
  347. if (SUCCEEDED(hr))
  348. return TRUE;
  349. if( hr == E_ADS_PROPERTY_NOT_FOUND && fIgnoreAttrNotFound)
  350. return TRUE;
  351. if (hr == HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR))
  352. {
  353. DWORD dwErr;
  354. WCHAR wszErrBuf[MAX_PATH+1];
  355. WCHAR wszNameBuf[MAX_PATH+1];
  356. ADsGetLastError(&dwErr, wszErrBuf, MAX_PATH, wszNameBuf, MAX_PATH);
  357. if ((LDAP_RETCODE)dwErr == LDAP_NO_SUCH_ATTRIBUTE && fIgnoreAttrNotFound)
  358. {
  359. return TRUE;
  360. }
  361. TRACE(_T("Extended Error 0x%x: %ws %ws (%s @line %d).\n"), dwErr,
  362. wszErrBuf, wszNameBuf, file, line);
  363. }
  364. else
  365. TRACE(_T("Error %08lx (%s @line %d)\n"), hr, file, line);
  366. return FALSE;
  367. }
  368. void DecorateName(LPWSTR outString, LPCWSTR inString)
  369. {
  370. wcscpy (outString, L"CN=");
  371. wcscat(outString, inString);
  372. }
  373. void FindNameByDN(LPWSTR outString, LPCWSTR inString)
  374. {
  375. LPWSTR p = wcsstr(inString, L"CN=");
  376. if(!p)
  377. p = wcsstr(inString, L"cn=");
  378. if(!p)
  379. wcscpy(outString, inString);
  380. else
  381. {
  382. p+=3;
  383. LPWSTR p1 = outString;
  384. while(*p == L' ') p++;
  385. while(*p != L',')
  386. *p1++ = *p++;
  387. *p1 = L'\0';
  388. }
  389. }
  390. static CString __DSRoot;
  391. HRESULT GetDSRoot(CString& RootString)
  392. {
  393. if(__DSRoot.GetLength() == 0)
  394. {
  395. CString sADsPath;
  396. BSTR bstrDomainFolder = NULL;
  397. HRESULT hr = S_OK;
  398. IADs* pDomainObject = NULL;
  399. DOMAIN_CONTROLLER_INFO *pInfo = NULL;
  400. // get the name of the Domain Controller
  401. DWORD dwErr = DsGetDcName(NULL, NULL, NULL, NULL, 0, &pInfo);
  402. if ( (dwErr != NO_ERROR) || (pInfo == NULL) )
  403. return HRESULT_FROM_WIN32(dwErr);
  404. ASSERT(pInfo->DomainControllerName);
  405. // strip off any backslashes or slashes
  406. CString sDCName = pInfo->DomainControllerName;
  407. while(!sDCName.IsEmpty())
  408. {
  409. if ('\\' == sDCName.GetAt(0) || '/' == sDCName.GetAt(0))
  410. sDCName = sDCName.Mid(1);
  411. else
  412. break;
  413. }
  414. int index = sDCName.Find(_T('.'));
  415. if(-1 != index)
  416. sDCName = sDCName.Left(index);
  417. sADsPath = _T("LDAP://") + sDCName;
  418. // Get the DC root DS object
  419. hr = ADsOpenObject(T2W((LPTSTR)(LPCTSTR)sADsPath), NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_USE_SIGNING | ADS_USE_SEALING, IID_IADs, (void**)&pDomainObject);
  420. if(FAILED(hr))
  421. return hr;
  422. // find the ADsPath of the DC root
  423. hr = pDomainObject->get_ADsPath(&bstrDomainFolder);
  424. if(FAILED(hr))
  425. return hr;
  426. pDomainObject->Release();
  427. pDomainObject = NULL;
  428. // construct the DN for the object where to put the registration information
  429. __DSRoot = W2T(bstrDomainFolder);
  430. SysFreeString(bstrDomainFolder);
  431. index = __DSRoot.ReverseFind(_T('/'));
  432. __DSRoot = __DSRoot.Mid(index + 1); // strip off the ADsPath prefix to get the X500 DN
  433. }
  434. RootString = __DSRoot;
  435. return S_OK;
  436. }
  437. /////////////////////////////////////////////////////////////////////////////
  438. // Min Chars Dialog Data Validation
  439. void AFXAPI DDV_MinChars(CDataExchange* pDX, CString const& value, int nChars)
  440. {
  441. ASSERT(nChars >= 1); // allow them something
  442. if (pDX->m_bSaveAndValidate && value.GetLength() < nChars)
  443. {
  444. TCHAR szT[32];
  445. wsprintf(szT, _T("%d"), nChars);
  446. CString prompt;
  447. AfxFormatString1(prompt, IDS_MIN_CHARS, szT);
  448. AfxMessageBox(prompt, MB_ICONEXCLAMATION, IDS_MIN_CHARS);
  449. prompt.Empty(); // exception prep
  450. pDX->Fail();
  451. }
  452. }
  453. #define MAX_STRING 1024
  454. //+----------------------------------------------------------------------------
  455. //
  456. // Function: ReportErrorEx
  457. //
  458. // Sysnopsis: Attempts to get a user-friendly error message from the system.
  459. //
  460. //-----------------------------------------------------------------------------
  461. UINT ReportErrorEx(HRESULT hr, int nStr, HWND hWnd, UINT MB_flags)
  462. {
  463. CString str;
  464. str.LoadString(nStr);
  465. return ReportErrorEx(hr, str, hWnd, MB_flags);
  466. }
  467. //+----------------------------------------------------------------------------
  468. //
  469. // Function: ReportErrorEx
  470. //
  471. // Sysnopsis: Attempts to get a user-friendly error message from the system.
  472. //
  473. //-----------------------------------------------------------------------------
  474. UINT ReportErrorEx(HRESULT hr, LPCTSTR Str, HWND hWnd, UINT MB_flags)
  475. {
  476. PTSTR ptzSysMsg;
  477. int cch;
  478. CString AppStr;
  479. CString SysStr;
  480. CString ErrTitle;
  481. CString ErrMsg;
  482. TRACE (_T("*+*+* ReportError called with hr = %lx"), hr);
  483. if (!hWnd)
  484. {
  485. hWnd = GetDesktopWindow();
  486. }
  487. try{
  488. if (Str)
  489. {
  490. AppStr = Str;
  491. }
  492. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  493. NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  494. (PTSTR)&ptzSysMsg, 0, NULL);
  495. if (!cch) { //try ads errors
  496. HMODULE adsMod;
  497. adsMod = GetModuleHandle (L"activeds.dll");
  498. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  499. adsMod, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  500. (PTSTR)&ptzSysMsg, 0, NULL);
  501. }
  502. if (!cch)
  503. {
  504. CString str;
  505. str.LoadString(IDS_ERR_ERRORCODE);
  506. SysStr.Format(str, hr);
  507. }
  508. else
  509. {
  510. SysStr = ptzSysMsg;
  511. LocalFree(ptzSysMsg);
  512. }
  513. ErrTitle.LoadString(IDS_ERR_TITLE);
  514. if(!AppStr.IsEmpty())
  515. {
  516. if(AppStr.Find(_T("%s")) != -1)
  517. ErrMsg.Format(AppStr, (LPCTSTR)SysStr);
  518. else
  519. {
  520. ErrMsg = AppStr;
  521. ErrMsg += SysStr;
  522. }
  523. }
  524. else
  525. {
  526. ErrMsg = SysStr;
  527. }
  528. if(MB_flags == 0) MB_flags = MB_OK | MB_ICONINFORMATION;
  529. return MessageBox(hWnd, (LPCTSTR)ErrMsg, (LPCTSTR)ErrTitle, MB_flags);
  530. }catch(CMemoryException&)
  531. {
  532. return MessageBox(hWnd, _T("No enought memory, please close other applications and try again."), _T("ACS Snapin Error"), MB_OK | MB_ICONINFORMATION);
  533. }
  534. }
  535. //+----------------------------------------------------------------------------
  536. //
  537. // Function: ReportError
  538. //
  539. // Sysnopsis: Attempts to get a user-friendly error message from the system.
  540. //
  541. //-----------------------------------------------------------------------------
  542. void ReportError(HRESULT hr, int nStr, HWND hWnd)
  543. {
  544. CString str;
  545. str.LoadString(nStr);
  546. ReportErrorEx(hr, str, hWnd, MB_OK | MB_ICONINFORMATION);
  547. }
  548. //+----------------------------------------------------------------------------
  549. //
  550. // Function: ReportError
  551. //
  552. // Sysnopsis: Attempts to get a user-friendly error message from the system.
  553. //
  554. //-----------------------------------------------------------------------------
  555. void ReportError(HRESULT hr, LPCTSTR Str, HWND hWnd)
  556. {
  557. ReportErrorEx(hr, Str, hWnd, MB_OK | MB_ICONINFORMATION);
  558. }
  559. BOOL CPageManager::OnApply()
  560. {
  561. if (!GetModified()) return FALSE;
  562. SetModified(FALSE); // prevent from doing this more than once
  563. std::list<CManagedPage*>::iterator i;
  564. for(i = m_listPages.begin(); i != m_listPages.end(); i++)
  565. {
  566. if ((*i)->GetModified())
  567. (*i)->OnApply();
  568. }
  569. return TRUE;
  570. }
  571. void CPageManager::AddPage(CManagedPage* pPage)
  572. {
  573. m_listPages.push_back(pPage);
  574. pPage->SetManager(this);
  575. }