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

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